【洛谷1357】花园
原题:
n<=1e15
首先要看清题,花圃是环形的而不是线形的
但是不妨先思考如果是线形该如何处理
如果n<=1e5做法很显然,f[i][j]表示直到第i个点状态为j的方案数,其中j是二进制压状态
然后可以发现转移都是f[i][j]+=f[i-1][k]的形式
自然想到矩阵乘方法
在转移矩阵A中,如果存在状态k能转移到状态j,那么a[k][j]为1否则为0
设矩阵乘的格式为AB=C,A是m阶转移方阵,B和C是m阶列向量
这样右侧列向量中b[j][1]就会乘上a[k][j](等于1),然后被加到c[k][1]上
如果a[k][j]为0则b[j][1]就不会被转移到c[k][1]上,等价于f[i-1][j]不会转移到f[i][k]
虽然矩阵乘没有交换律,但是只要每次把转移矩阵乘在最左边即可
即AB=C变成AAB=A^2B=AC,这样就能转移任意次
最后考虑怎么把线形情况扩展到环形情况
首先可以快速幂出n-m次转移的转移矩阵,然后枚举前m个物品
然后对每个枚举到的状态t,先令列向量b[t][1]=1,然后乘上转移矩阵得到答案向量C
从C向量里挑出不会和状态t冲突的后m个物品的状态,累计答案
代码:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 #define LL long long 5 const int mo=1000000007; 6 int m,o; LL n; 7 struct mtx{ 8 LL a[32][32]; 9 mtx(){ 10 for(int i=0;i<32;++i)for(int j=0;j<32;++j) 11 a[i][j]=0; 12 } 13 mtx(int x){ 14 for(int i=0;i<32;++i)for(int j=0;j<32;++j) 15 a[i][j]=0; 16 for(int i=0;i<32;++i) 17 a[i][i]=1; 18 } 19 mtx operator*(mtx y){ 20 mtx z; 21 for(int i=0;i<32;++i)for(int j=0;j<32;++j) 22 for(int k=0;k<32;++k) 23 z.a[i][j]=(z.a[i][j]+a[i][k]*y.a[k][j])%mo; 24 return z; 25 } 26 void ot(){ 27 for(int i=0;i<(1<<m);++i){ 28 for(int j=0;j<(1<<m);++j) 29 printf("%lld ",a[i][j]); 30 printf("\n"); 31 } 32 cout<<endl; 33 } 34 }a; 35 mtx qcp(mtx x,LL y){ 36 mtx z=x,bwl(1); 37 for(;y;y>>=1){ 38 if(y&1) bwl=z*bwl; 39 z=z*z; 40 } 41 return bwl; 42 } 43 bool chck(int x){ 44 int bwl=0; 45 for(;x;x>>=1) bwl+=(x&1); 46 return bwl<=o; 47 } 48 bool chck2(int x,int y){ 49 for(;x;x>>=1){ 50 y>>=1; 51 if(x&1) y|=(1<<(m-1)); 52 if(!chck(y)) return false; 53 } 54 return true; 55 } 56 int main(){ 57 cin>>n>>m>>o; 58 for(int i=0;i<(1<<m);++i)if(chck(i)){ 59 a.a[i>>1][i]=1; 60 if(chck(i>>1|(1<<(m-1)))) 61 a.a[i>>1|(1<<(m-1))][i]=1; 62 } 63 mtx tmp=qcp(a,n-m); 64 LL bwl=0; 65 for(int i=0;i<(1<<m);++i)if(chck(i)){ 66 mtx ans; 67 ans.a[i][0]=1; 68 ans=tmp*ans; 69 for(int j=0;j<(1<<m);++j)if(chck2(i,j)) 70 bwl=(bwl+ans.a[j][0])%mo; 71 } 72 cout<<bwl; 73 /* 74 mtx tmp=qcp(a,n-1); 75 mtx ans; 76 ans.a[0][0]=1,ans.a[1<<(m-1)][0]=1; 77 ans=tmp*ans; 78 LL bwl=0; 79 for(int i=0;i<(1<<m);++i) bwl=(bwl+ans.a[i][0])%mo; 80 cout<<bwl<<endl; 81 */ 82 return 0; 83 }