• luogu1357花园(矩阵运算)(状压DP)


    不得不说本蒻做这个题目的时候内心是很蒙蔽的qwq
    推了规律找错了结果还没有暴力的分数高qwq......

    开数组(f[i][j])来记录前i个花圃,(这里运用到状压的思想)其中最近的m个的状态(二进制,1表示C,0表示P),然后因为这个状态是可以递推下一个状态的(比如说1m到2m+1),然后我们发现每一次的状态转移都可以用同一个矩阵实现,那么该题目就可以用矩阵快速幂来加速计算。因为题目中是一个环状,那么转换n次一定还是原先的状态。那么题目就转换成了一个合法状态(这个需要预先判断出来)转移n次到自己的方案数量qwq。f数组的第一维也不需要了,那么直接(f[j])乘以矩阵的n次方依次累加就是答案数量了qwq

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int M=5,p=1000000007;
    long long n,m,k,ans=0;
    long long f[1<<M],a[1<<M][1<<M];
    int MAX,cnt;
    bool pd[1<<M];
    inline void mulself(long long a[1<<M][1<<M]) {
        long long c[1<<M][1<<M];
        memset(c,0,sizeof(c));
        for(int i=0;i<MAX;++i)
            for(int j=0;j<MAX;++j)
                for(int k=0;k<MAX;++k)
                    c[i][j]=(c[i][j]+a[i][k]*a[k][j])%p;
        memcpy(a,c,sizeof(c));
    }
    inline void mul(long long f[1<<M],long long a[1<<M][1<<M]) 
    {
        long long c[1<<M];
        memset(c,0,sizeof c);
        for(int j=0;j<MAX;++j)
            for(int k=0;k<MAX;++k)
                c[j]=(c[j]+f[k]*a[k][j])%p;
        memcpy(f,c,sizeof(c));
    }
    //以上是矩阵乘法的内容 
    int main() {
        scanf("%lld%lld%lld",&n,&m,&k);
        MAX=1<<m;
        //最大的情况统计 
        for(int i=0;i<MAX;++i) {
            cnt=0;
            for(int j=0;j<m;++j)
                if(i&1<<j)++cnt;
            if(cnt<=k) pd[i]=true;
            //记录合法方案 
        }
        for(int i = 0; i < MAX; ++i)
            if(pd[i]) //这个是合法状态 
    		{
                memset(f,0,sizeof(f)); 
    			f[i]=1;//初始化该状态的方案数为1 
                memset(a,0,sizeof(a)); 
                for(int j=0;j<MAX;++j) //搜寻转移的下一个状态 
    				if(pd[j])//如果这个状态合法 
                    	a[j>>1][j]=1,a[(j>>1)+(1<<(m-1))][j]=1;//记录状态之间转移是合法的
    					//进行矩阵快速幂加速运算 
                for(long long y=n;y;y>>=1,mulself(a))
                    if(y&1)
                        mul(f,a);
                ans=(ans+f[i])%p;//统计答案 
             }
        printf("%lld
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    Linux PCI网卡驱动的详细分析
    moand的编程学形式:一个(高阶)类型包办程序的组织--类型关乎复合
    范畴论完全解读:函子是范畴(高阶类型)间的映射
    函数式编程从起点到终点
    锁的本质:操作的序列化
    并发编程概述--C#并发编程经典实例
    异步IO的概念
    基于事件的并发编程
    runloop是iOS系统上的actor模式
    Monad、Actor与并发编程--基于线程与基于事件的并发编程之争
  • 原文地址:https://www.cnblogs.com/fengxunling/p/9712045.html
Copyright © 2020-2023  润新知