题解
首先考虑$N \leq 10^5$
很容易想到动态规划
我们不难设计状态
$f_{i,j}$表示方案数
$i$表示当前已经确定了$i$个位置
$j$表示第$j-m+1~j$的二进制状态
和状态转移方程
$f_{i,j}=\Sigma{f_{i-1,k}}(k,j都合法且k后接一位即为j)$
故我们只需要预处理出所有状态是否合法和各个状态之间能否转换,然后动态规划即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MOD=1e9+7,MAXN=1e5+50,MAXM=8,MAXP=70; 5 inline void add(int &x,int y){ 6 x=(x+y)%MOD; 7 } 8 LL N; 9 int M,K; 10 bool bin[MAXM],leg[MAXP]/*״̬ÊÇ·ñºÏ·¨*/,tran[MAXP][MAXP]/*תÒÆÊÇ·ñºÏ·¨*/; 11 inline void sign(){ 12 int cur=0,nxt=0,sum[MAXM]={0}; 13 for(int i=1;i<=M;i++) 14 cur=cur<<1|bin[i]; 15 for(int i=2;i<=M+1;i++) 16 nxt=nxt<<1|bin[i]; 17 for(int i=1;i<=M+1;i++) 18 sum[i]=sum[i-1]+bin[i]; 19 if(sum[M]>K||sum[M+1]-sum[1]>K) 20 return; 21 leg[cur]=leg[nxt]=1; 22 tran[cur][nxt]=1; 23 } 24 void dfs(int x){/*ö¾Ù²¢±ê¼ÇËùÓкϷ¨µÄ״̬*/ 25 if(x==M+2){ 26 sign(); 27 return; 28 } 29 bin[x]=0; 30 dfs(x+1); 31 bin[x]=1; 32 dfs(x+1); 33 } 34 int f[MAXN][MAXP],maxp,ans; 35 inline void dp(int S){/*Çó½â´ÓÌض¨×´Ì¬³ö·¢µÄ·½°¸Êý*/ 36 memset(f,0,sizeof(f)); 37 f[M][S]=1; 38 for(int i=M+1;i<=M+N;i++) 39 for(int j=0;j<maxp;j++) 40 for(int k=0;k<maxp;k++) 41 if(tran[j][k])/*´æÔÚjµ½kµÄתÒÆ*/ 42 add(f[i][j],f[i-1][k]); 43 add(ans,f[N+M][S]); 44 } 45 int main(){ 46 scanf("%lld%d%d",&N,&M,&K); 47 dfs(1); 48 maxp=1<<M; 49 for(int i=0;i<maxp;i++) 50 if(leg[i]) 51 dp(i); 52 printf("%d",ans); 53 return 0; 54 }
然后考虑$N \leq 10^{15}$
观察我们预处理出的邻接矩阵(各个状态之间能否转换的矩阵),可以发现这实际上是一个传递闭包问题(类似于Floyd),每一个状态都会按着这个矩阵操作N次
故可以使用矩阵快速幂优化,代码就很简单了
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MOD=1e9+7,MAXN=1e5+50,MAXM=8,MAXP=70; 5 inline void add(LL &x,LL y){ 6 x=(x+y)%MOD; 7 } 8 LL N,maxp,ans,M,K; 9 bool bin[MAXM],leg[MAXP]; 10 struct matrix{ 11 LL a[MAXP][MAXP]; 12 matrix (){ 13 memset(a,0,sizeof(a)); 14 } 15 friend matrix operator*(matrix x,matrix y){ 16 matrix ret; 17 for(int i=0;i<maxp;i++) 18 for(int j=0;j<maxp;j++) 19 for(int k=0;k<maxp;k++) 20 add(ret.a[i][j],x.a[i][k]*y.a[k][j]); 21 return ret; 22 } 23 }tran,a; 24 inline void sign(){ 25 int cur=0,nxt=0,sum[MAXM]={0}; 26 for(int i=1;i<=M;i++) 27 cur=cur<<1|bin[i]; 28 for(int i=2;i<=M+1;i++) 29 nxt=nxt<<1|bin[i]; 30 for(int i=1;i<=M+1;i++) 31 sum[i]=sum[i-1]+bin[i]; 32 if(sum[M]>K||sum[M+1]-sum[1]>K) 33 return; 34 leg[cur]=leg[nxt]=1; 35 tran.a[cur][nxt]=1; 36 } 37 void dfs(int x){ 38 if(x==M+2){ 39 sign(); 40 return; 41 } 42 bin[x]=0; 43 dfs(x+1); 44 bin[x]=1; 45 dfs(x+1); 46 } 47 inline matrix pow(matrix x,LL y){ 48 matrix ret=x; 49 y--; 50 while(y){ 51 if(y&1){ 52 ret=ret*x; 53 } 54 x=x*x; 55 y>>=1; 56 } 57 return ret; 58 } 59 int main(){ 60 scanf("%lld%lld%lld",&N,&M,&K); 61 maxp=1<<M; 62 dfs(1); 63 a=pow(tran,N); 64 for(int i=0;i<maxp;i++) 65 if(leg[i]) 66 add(ans,a.a[i][i]); 67 printf("%lld",ans); 68 return 0; 69 }