【洛谷】P1357 花园(状压+矩阵快速幂)

题目

传送门:QWQ

分析

因为m很小,考虑把所有状态压成m位二进制数。

那么总状态数小于$ 2^5 $。

如果状态$ i $能转移到$ j $,那么扔进一个矩阵,n次方快速幂一下。

答案是对角线之和,是转移n次后回来的方案数。

代码

 1 #include <bits/stdc++.h>
 2 typedef long long ll;
 3 const int maxn=100;
 4 const ll MOD=1000000007;
 5 using namespace std;
 6 ll tot; int sta[maxn];
 7 struct Matrix{
 8     ll m[maxn][maxn];
 9     Matrix(){memset(m,0,sizeof(m));}
10 };
11 Matrix operator * (const Matrix& a,const Matrix& b){
12     Matrix ans;
13     for(int i=0;i<=tot;i++)
14         for(int j=0;j<=tot;j++)
15             for(int k=0;k<=tot;k++)
16                 ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%MOD;
17     return ans;
18 }
19 Matrix a,ans,f,tmp;
20 int main(){
21     ll n,m;int k;
22     cin>>n>>m>>k;
23     tot=(1<<m)-1;
24     for(int i=0;i<=tot;i++){
25         int num=0,x=i;
26         while(x){ if(x&1)num++; x>>=1; }
27         if(num<=k){
28             sta[i]=true;
29             a.m[i>>1][i]=1;
30             a.m[(i>>1)+(1<<(m-1))][i]=1;
31         }
32     }
33 
34     for(int i=0;i<maxn;i++) tmp.m[i][i]=1;
35     while(n){
36         if(n&1) tmp=tmp*a;
37         a=a*a;
38         n>>=1;
39     }
40 
41     // for(int i=0;i<=tot;i++,puts(""))
42     //     for(int j=0;j<=tot;j++)
43     //         printf("%5d ",tmp.m[i][j]);
44     ll cnt=0;
45     for(int i=0;i<=tot;i++){
46         if(sta[i]){
47             cnt=(cnt+tmp.m[i][i])%MOD;
48         }
49     }
50     cout<<cnt<<endl;
51     return 0;
52 }

猜你喜欢

转载自www.cnblogs.com/noblex/p/9447731.html