zoukankan      html  css  js  c++  java
  • 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;
    }

    代码还是比较好写的

  • 相关阅读:
    微众银行面试小总结
    关于撑开父容器高度的小探讨
    2015年9月阿里校招前端工程师笔试题
    高性能JavaScript 重排与重绘
    高性能JavaScript DOM编程
    纯CSS3动画实现小黄人
    JS+css3实现图片画廊效果总结
    新游戏《机械险境》
    Twitter "fave"动画
    fragment 与 activity
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9583851.html
Copyright © 2011-2022 走看看