[luogu1357] 花园 [dp+矩阵快速幂]

题面:

传送门

思路:

把P形花圃记录为0,C形记录为1,那么一段花圃就可以状态压缩成一个整数

那么,我们可以有这样的状压dp:

dp[i][S]表示前i个花圃,最后m个的状态为S的情况

如果这是一条链的花圃,那么直接状压转移就可以了,但是这道题是一个环

一个环上,前m-1个花圃会影响到后m-1个花圃的状态

因此我们考虑把这个环后面再“长出”m个花圃来,消除这种影响

具体做法是:

枚举所有合法的状态S,令dp[1][S]=1,其余为零,代表前m个的状态确定了然后递推

最后把dp[n+1][S]加入答案,代表最后m个(第1~0-m+1个)的状态为S

由于n比较大,因此需要预处理出转移,写成矩阵快速幂的形式(因为这里的递推显然是线性的)

 

Code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define mx 1e16
 6 #define ll long long
 7 using namespace std;
 8 inline ll read(){
 9     ll re=0,flag=1;char ch=getchar();
10     while(ch>'9'||ch<'0'){
11         if(ch=='-') flag=-1;
12         ch=getchar();
13     }
14     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
15     return re*flag;
16 }
17 ll n,m,K,MOD=1e9+7;
18 struct ma{
19     ll a[50][50],n,m;
20     ma(){memset(a,0,sizeof(a));n=m=0;}
21     void clear(){memset(a,0,sizeof(a));n=m=0;}
22     const ma operator *(const ma &b){
23         ma re;re.n=n;re.m=b.m;ll i,j,k;
24         for(i=1;i<=n;i++){
25             for(j=1;j<=b.m;j++){
26                 for(k=1;k<=m;k++){
27                     re.a[i][j]+=a[i][k]*b.a[k][j];
28                     re.a[i][j]%=MOD;
29                 }
30             }
31         }
32         return re;
33     }
34     const void operator =(const ma &b){
35         n=b.n;m=b.m;ll i,j;
36         for(i=1;i<=n;i++) for(j=1;j<=m;j++) a[i][j]=b.a[i][j];
37     }
38 }A,B,ans;
39 ll st[50],cnt,in[50];
40 ll count(ll x){
41     ll re=0;
42     while(x){
43         if(x&1) re++;
44         x>>=1;
45     }
46     return re;
47 }
48 ma ppow(ma x,ma y,ll t){
49     while(t){
50         if(t&1) x=x*y;
51         y=y*y;t>>=1;
52     }
53     return x;
54 }
55 int main(){
56     n=read();m=read();K=read();
57     ll i,t1,t2,j;
58     for(i=0;i<(1<<m);i++){
59         if(count(i)<=K) st[++cnt]=i,in[i]=cnt;
60     }
61     A.n=1;A.m=B.n=B.m=cnt;
62     for(i=1;i<=cnt;i++){
63         t1=(st[i]<<1)&((1<<m)-1);t2=t1+1;
64         if(in[t1]) B.a[i][in[t1]]=1;
65         if(in[t2]) B.a[i][in[t2]]=1;
66     }
67     ll re=0;
68     for(i=1;i<=cnt;i++){
69         A.clear();A.a[1][i]=1;A.n=1;A.m=cnt;
70         ans=ppow(A,B,n);
71         re+=ans.a[1][i];re%=MOD;
72     }
73     printf("%lld",re%MOD);
74 }

 

posted @ 2018-03-31 12:39  dedicatus545  阅读(256)  评论(0编辑  收藏  举报