P1357 花园

传送门

花圃只有两种

m最大为5

可以把C形的花圃看成 1 ,其他的看成 0

每m个花圃看成一个状态,只有 2^5 种状态

显然状态可以互相转移

比如说第 1~5 个花圃为一个状态

它可以转移到第 2~6 个花圃的一个状态

那筛一下可以转移的状态,然后跑DP就可以了

设 f [ i ] [ j ] 表示状态为 j,此状态的开头的位置为 i,那么

f [ i ] [ j ] += f [ i-1 ] [ k ](k可以转移到 j)

但是因为花圃是环形,所以枚举开始的状态 j,然后 i 要从 1 到 n(而不是从 1 到 n-m),把 f [ n ] [ j ] 加到答案里

那么枚举开头的每个状态

把开头的每个状态分别加起来就行了

这样有 80 分

因为每个转移都是从前面一个状态转过来的

所以考虑矩阵优化

那么初始状态矩阵 A[ i ][ i ] = 1(表示以第 i 种状态开始,刚开始只有 i 有一种方案)

注意不是A[1][ i ] = 1,因为每种初始状态要分开讨论

构造一个 2^m * 2^m 的转移矩阵P:

如果 i 可以转移到 j

那么显然 P[ j ][ i ] = 1;

然后就可以跑过了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mo=1000000007;
ll n,m,K,M;
struct matrix
{
    ll a[100][100];
    matrix() { memset(a,0,sizeof(a)); }
    matrix operator * (matrix &tmp){
        matrix c;
        for(int i=1;i<(1<<m);i++)
            for(int j=1;j<(1<<m);j++)
                for(int k=1;k<(1<<m);k++)
                    c.a[i][j]=(c.a[i][j]+(a[i][k]*tmp.a[k][j])%mo)%mo;
        return c;
    }
}p;
int t[100],cnt;
inline void pre()
{
    for(int i=0;i<M;i++)
    {
        int num=0;
        for(int j=0;j<m;j++) if( i&(1<<j) ) num++;
        if(num<=K) t[++cnt]=i;
    }
    for(int i=1;i<=cnt;i++)
        for(int j=1;j<=cnt;j++)
        {
            bool flag=1;
            int x=t[i],y=t[j]>>1;
            for(int k=0;k<m-1;k++)
            {
                if( (x&1) != (y&1) )
                {
                    flag=0;
                    break;
                }
                x>>=1; y>>=1;
            }
            if(flag) p.a[j][i]=1;
        }
}//预处理
inline matrix ksm(matrix x,ll y)
{
    matrix res;
    for(int i=0;i<(1<<m);i++) res.a[i][i]=1;
    while(y)
    {
        if(y&1) res=res*x;
        x=x*x;
        y>>=1;
    }
    return res;
}
int main()
{
    cin>>n>>m>>K;
    M=(1<<m);
    pre();
    p=ksm(p,n);
    ll ans=0;
    for(int i=1;i<=cnt;i++) ans=(ans+p.a[i][i])%mo;
    cout<<ans;
    return 0;
}

 

代码还是比较好写的

posted @ 2018-09-04 13:26  LLTYYC  阅读(198)  评论(0编辑  收藏  举报