【洛谷】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 }