2021牛客OI赛前集训营-提高组(第三场)
一个长度为nnn的数组aaa,每秒都会变成一个长度为n−1n-1n−1的新数组a′a'a′,其变化规则如下
最终数组经过n−1n-1n−1秒后变为一个数字,求这个数字对109+710^9+7109+7取模后的结果。
通过打表可以发现,当nnn为偶数时,aia_iai对答案的贡献为(−1)t×Cn/2−1t(-1)^t\times C_{n/2-1}^{t}(−1)t×Cn/2−1t,其中t=⌊i−12⌋t=\lfloor\dfrac{i-1}{2}\rfloort=⌊2i−1⌋。
如果nnn为偶数,则直接用上面的规律来求即可。如果nnn为奇数,那么操作一次,将nnn变为偶数,再用上面的规律来求即可。
当然,考场上可以直接用打表发现的规律,但学习要严谨,所以下面给出证明。
用多项式a1x+a2x2+⋯+anxna_1x+a_2x^2+\cdots+a_nx^na1x+a2x2+⋯+anxn表示当前的状态,用xix^ixi的系数表示当前第iii个位置的值。
那么nnn每减去2,则多项式乘上(1−1x2)(1-\dfrac{1}{x^2})(1−x21)。
对于偶数的nnn,多项式要乘上(1−1x2)n/2−1(1+1x)=(1−Cn/2−111x2+Cn/2−121x4−⋯)(1+1x)(1-\dfrac{1}{x^2})^{n/2-1}(1+\dfrac 1x)=(1-C_{n/2-1}^1\dfrac{1}{x^2}+C_{n/2-1}^2\dfrac{1}{x^4}-\cdots)(1+\dfrac 1x)(1−x21)n/2−1(1+x1)=(1−Cn/2−11x21+Cn/2−12x41−⋯)(1+x1)。最后的答案就是xxx的系数。
我们考虑如何求xxx的系数。对于最初多项式中的xix^ixi,
其中t=⌊i−12⌋t=\lfloor\dfrac{i-1}{2}\rfloort=⌊2i−1⌋。
那么就可以得到开头的结论。
时间复杂度为O(n)O(n)O(n)。
#include
using namespace std;
int n;
long long ans=0,a[100005],jc[100005],ny[100005];
long long mod=1000000007;
long long mi(long long t,long long v){if(!v) return 1;long long re=mi(t,v/2);re=re*re%mod;if(v&1) re=re*t%mod;return re;
}
long long C(int x,int y){return jc[x]*ny[y]%mod*ny[x-y]%mod;
}
int main()
{scanf("%d",&n);jc[0]=1;for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;ny[n]=mi(jc[n],mod-2);for(int i=n-1;i>=0;i--) ny[i]=ny[i+1]*(i+1)%mod;for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}if(n==1){printf("%d",(a[1]%mod+mod)%mod);return 0;}if(n%2==1){--n;for(int i=1;i<=n;i++){a[i]=(a[i]-a[i+1]+mod)%mod;}}for(int i=1;i<=n;i++){int x=(n-1)/2,y=(i-1)/2;if(y&1) ans=(ans-C(x,y)*a[i]%mod+mod)%mod;else ans=(ans+C(x,y)*a[i]%mod+mod)%mod;}printf("%lld",ans);return 0;
}