2021牛客OI賽前集訓營-交替【生成函式】
阿新 • • 發佈:2021-10-09
正題
題目連結:https://ac.nowcoder.com/acm/contest/20108/B
題目大意
給出一個長度為\(n\)的序列\(a\),每次
- 如果\(n\)是偶數,則對於所有的\(i<n\)令新的\(a'_i=a'_i+a'_{i+1}\)
- 如果\(n\)是奇數,則對於所有的\(i<n\)令新的\(a'_i=a'_i-a'_{i+1}\)
\(1\leq n\leq 10^5,1\leq a_i\leq 10^9\)
解題思路
對於一個位置它操作\(k\)次之後肯定可以用後面的若干個數表示,設多項式\(f_k(x)=\sum_{i=0}^{\infty }b_ix^i\)有\(a'_{p}=\sum_{i=0}^nb_i\times a_{p+i}\)
那麼對於這個多項式如果\(n\)是奇數那麼有\(f_k(x)=f_{k-1}(x)\times (1+x)\),否則\(f_k(x)=f_{k-1}(x)\times (1-x)\)。
也就是每次\((1+x)\)和\((1-x)\)交替乘\(n-1\)次,如果\(n\)是奇數,那麼
\[f_{n-1}(x)=((1+x)(1-x))^{\frac{n-1}{2}}=(1-x^2)^{\frac{n-1}{2}} \]用二項式定理拆開暴力算就好了,
如果\(n\)是偶數就直接再乘個\(1+x\)就好了。
時間複雜度:\(O(n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e5+10,P=1e9+7; ll n,ans,fac[N],inv[N],f[N]; ll C(ll n,ll m) {return fac[n]*inv[m]%P*inv[n-m]%P;} signed main() { scanf("%lld",&n);n--; inv[0]=inv[1]=fac[0]=1; for(ll i=2;i<=n;i++)inv[i]=P-(P/i)*inv[P%i]%P; for(ll i=1;i<=n;i++)inv[i]=inv[i-1]*inv[i]%P,fac[i]=fac[i-1]*i%P; for(ll i=0;i<=n/2;i++) f[i*2]=(i&1)?(P-C(n/2,i)):(C(n/2,i)); if(n&1){ for(ll i=n;i>=1;i--) f[i]=f[i]+f[i-1]; } for(ll i=0,x;i<=n;i++) scanf("%lld",&x),(ans+=f[i]*x%P)%=P; printf("%lld\n",ans); return 0; }