洛谷 P1357 花园

原题链接

题解

首先考虑$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 }
View Code

然后考虑$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 }
View Code

猜你喜欢

转载自www.cnblogs.com/guoshaoyang/p/11139346.html