【[CQOI2018]交錯序列】
阿新 • • 發佈:2019-01-01
序列 這一 turn line 一位 display %d void long long 表示進行到第\(i\)位上,這個\(\sum\)的第\(j\)次方項,最後一位填的是\(0/1\)
這個題簡直有毒,\(O((a+b)^3logn)\)的做法不卡常只比\(O(2^n*n)\)多\(10\)分
看到\(a\)和\(b\)簡直小的可憐,於是可以往矩陣上聯想
發現這個柿子有些特殊,好像可以二項式定理搞一搞
於是\(x^ay^b\)可以寫成\((n-y)^ay^b\)
於是接下來就二項式定理好了
\[(n-y)^ay^b=\sum_{r=0}^a\binom{a}{r}n^{a-r}*(-y)^r*y^b\]
\[=\sum_{r=0}^a\binom{a}{r}n^{a-r}*(-1)^r*y^{b+r}\]
發現好像可以用矩陣來維護這個\(\sum\)的每一項
先列一下\(dp\)的方程,設\(dp[i][j][0/1]\)
如果這一位填\(0\),對答案並沒有什麽貢獻,但是前面填\(0/1\)都是可以的,於是\(dp[i][j][0]=dp[i-1][j][0]+dp[i-1][j][1]\)
如果這一位填的是\(1\),那麽前面的那一位只能填\(0\),\(y\)增加了\(1\),所以答案變成了\((y+1)^j\)
還是用二項式定理
\[(y+1)^j=\sum_{k=0}^j\binom{j}{k}y^k\]
所以也就可以得到
\[dp[i][j][1]=\sum_{k=0}^j\binom{j}{k}*dp[i-1][k][0]\]
矩陣維護就可以了
#include<iostream> #include<cstring> #include<cstdio> #define re register #define maxn 185 #define LL long long LL a[maxn][maxn],ans[maxn][maxn]; int sz; int T,A,b,P; LL c[maxn][maxn]; inline void did_a() { LL mid[maxn][maxn]; for(re int i=1;i<=sz;i++) for(re int j=1;j<=sz;j++) mid[i][j]=a[i][j],a[i][j]=0; for(re int i=1;i<=sz;i++) for(re int k=1;k<=sz;k++) for(re int j=1;j<=sz;j++) { a[i][j]+=mid[i][k]*mid[k][j]; if(a[i][j]>P) a[i][j]%=P; } } inline void did_ans() { LL mid[maxn][maxn]; for(re int i=1;i<=sz;i++) for(re int j=1;j<=sz;j++) mid[i][j]=ans[i][j],ans[i][j]=0; for(re int i=1;i<=sz;i++) for(re int k=1;k<=sz;k++) for(re int j=1;j<=sz;j++) { ans[i][j]+=mid[i][k]*a[k][j]; if(ans[i][j]>P) ans[i][j]%=P; } } inline LL quick(LL a,int b) { LL S=1; while(b) { if(b&1) S=S*a%P; b>>=1; a=a*a%P; } return S; } inline void Mat_quick(int b) { while(b) { if(b&1) did_ans(); b>>=1; did_a(); } } int main() { scanf("%d%d%d%d",&T,&A,&b,&P); c[0][0]=1; for(re int i=1;i<=A+b;i++) c[i][0]=c[i][i]=1; for(re int i=1;i<=A+b;i++) for(re int j=1;j<i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%P; sz=(A+b+1)*2; for(re int i=1;i<=sz;i++) ans[i][i]=1; for(re int i=1;i<=(sz>>1);i++) a[i][i]=a[i+sz/2][i]=1; for(re int i=1;i<=(sz>>1);i++) for(re int j=i+sz/2;j<=sz;j++) a[i][j]=c[j-1-sz/2][i-1]; Mat_quick(T); LL Ans=0; for(re int i=0;i<=A;i++) if(i&1) Ans=(Ans-c[A][i]*quick(T,A-i)%P*(ans[1][i+1+b]+ans[1][i+1+b+sz/2]%P)%P+P)%P; else Ans=(Ans+c[A][i]*quick(T,A-i)%P*(ans[1][i+1+b]+ans[1][i+1+b+sz/2]%P))%P; std::cout<<Ans; return 0; }
【[CQOI2018]交錯序列】