luogu P1357 花园
题目链接
题解
开始读错题了,QAq,只看了m<=n,然后这怎je做啊QAq
用一种可行状态做环的起始部分,维护后m个的状态,进行装压dp,在后边插可行状态,那么如何保证环呢 ,
由于是环,所以转移n次后,贡献有用的方案是,末装态与原来相同的方案 ,(也就是末状态转移为初状态的方案) 当然,状态必须在满足条件的状态中转移 ->80pts
对于转移矩阵,矩阵快速幂优化装态转移的递推 ->100pts
那么状态S答案为矩阵[S][S]的值
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
const int mod = 1000000007;
LL n,m,k,S;
const int maxs = (1 << 5) + 7;
struct Matrix {
LL a[maxs][maxs];
Matrix(){memset(a,0,sizeof a); }
Matrix operator * (const Matrix & x) const {
Matrix ret;
for(int k = 0;k <= S;++ k)
for(int i = 0;i <= S;++ i)
for(int j = 0;j <= S;++ j)
ret.a[i][j] = (ret.a[i][j] + a[i][k] * x.a[k][j]) % mod;
return ret;
}
} t,ans;
bool can[maxs];
void connect(int s,int num) {
can[s] = 1;int pre = s >> 1;
t.a[pre][s] = 1;
if(num == k && !(s & 1)) return;
t.a[pre | (1 << (m - 1))][s] = 1;
}
void dfs(int x,int num,int s) {
if(x == m + 1) {connect(s,num);return;}
dfs(x + 1,num,s);
if(num < k) dfs(x + 1,num + 1,s | (1 << (x - 1))) ;
}
void qpow() {
for(int i = 0;i <= S;++ i) ans.a[i][i] = 1;
for(;n;n >>= 1,t = t * t)
if(n & 1) ans = ans * t;
}
int main() {
scanf("%lld%lld%lld",&n,&m,&k);
S = (1 << m) - 1;
dfs(1,0,0);
qpow();
LL Ans = 0;
for(int i = 0;i <= S;++ i) if(can[i])Ans = (Ans + ans.a[i][i]) % mod;
printf("%lld\n",Ans);
return 0;
}