實際上就是這樣一個問題,一個序列僅由1和0組成,問n位不帶101和111子序列有多少個,結果模m
話說這是集訓的一道題,當時完全沒思路,今天做了一下,還是沒有做出來,不過好歹還會用最裸的記憶化搜索。。。但肯定超時(話說集訓那時真的弱爆了。。超弱的1B)
看了下解題報告,發現1維DP既能搞定,再用矩陣二分。。其實這個DP怎么推出來的呢?就是分類討論出來的。。(哎,其實真的很簡單,但偏偏想亂了,這方面題果斷刷的太少)。。設F(n)為n位滿足題意的數列數。。。當第1位為0時,F(n)=F(n-1),若第二位為1,那么肯定第三位必須要為0,這個時候在看第二位,若第二位為0時,F(n)=F(n-3),若第二位為1時,那嗎只有1100...滿足條件,而第5位無論是神馬也滿足,F(n)=F(n-4)...所以F(n)=F(n-1)+F(n-3)+F(n-4)...矩陣快速冪即可。。(注意雖然是3項,但矩陣一定是4項,剛開始因為寫成3項就WA了。。。)
#include <iostream> #define N 25 #define M 4 #define cl(a) memset(a,0,sizeof(a)) #define ss(a) scanf("%d",&a) using namespace std; int n,m,f[5],u[N][5][5],t[5]; const int a[5]={0,2,4,6,9}; const int b[5]={0,1,0,1,1}; void init() { int i,j; cl(f);cl(u); for (i=1;i<=M;i++) f[i]=a[5-i]%m; for (i=1;i<=M;i++) for (j=1;j<=M;j++) if (i==1) u[0][i][j]=b[j]; else if (i==j+1) u[0][i][j]=1; else u[0][i][j]=0; } void mi(int x) { int i,j,k; for (i=1;i<=M;i++) for (j=1;j<=M;j++) { int r=0; for (k=1;k<=M;k++) r=(r+u[x-1][i][k]*u[x-1][k][j])%m; u[x][i][j]=r; } return; } void mul(int x) { int i,j,k; cl(t); for (i=1;i<=M;i++) for (j=1;j<=M;j++) t[i]=(t[i]+u[x][i][j]*f[j])%m; for (i=1;i<=M;i++) f[i]=t[i]; } void bin(int n1) { int i=0; while (n1>0) { if (n1&1) mul(i); i++; n1>>=1; } } int main() { int i; while (ss(n)!=EOF) { ss(m); if (n<=4) { printf("%d\n",a[n]%m); continue; } init(); for (i=1;i<N;i++) mi(i); bin(n-4); int res=f[1]; printf("%d\n",res); } return 0; }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。