luogu P1357 花园

题目链接

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; 
} 
posted @ 2018-07-04 21:06  zzzzx  阅读(103)  评论(0编辑  收藏  举报