• BZOJ 2004 公交线路(状压DP+矩阵快速幂)


    注意到每个路线相邻车站的距离不超过K,也就是说我们可以对连续K个车站的状态进行状压。

    然后状压DP一下,用矩阵快速幂加速运算即可。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <algorithm>
    
    #define MAXN 140
    #define MOD 30031
    
    using namespace std;
    
    struct Matrix
    {
        int num[MAXN][MAXN];
        int n,m; //n*m大小矩阵
        void setOne(int a,int b)
        {
            n=a,m=b;
            for(int i=1;i<=min(n,m);i++) num[i][i]=1;
        }
        Matrix() { memset(num,0,sizeof(num)); }
    }T,A,one;
    
    Matrix operator*(Matrix a,Matrix b)
    {
        Matrix c;
        c.n=a.n,c.m=b.m;
        for(int i=1;i<=c.n;i++)
            for(int j=1;j<=c.m;j++)
                for(int k=1;k<=a.m;k++)
                    c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j])%MOD;
        return c;
    }
    
    Matrix fastPow(Matrix base,int pow)
    {
        Matrix ans;
        ans.setOne(base.n,base.m);
        while(pow)
        {
            if(pow&1) ans=ans*base;
            base=base*base;
            pow>>=1;
        }
        return ans;
    }
    
    int calc(int x) //计算x的二进制中1的个数
    {
        int sum=0;
        while(x)
        {
            sum++;
            x-=x&(-x); //x去掉最后一个1
        }
        return sum;
    }
    
    int n,k,p,goal; //goal是目标状态
    
    bool canConvert(int to,int from) //检查状态from能否一步转移到状态to
    {
        from=(from-(1<<(p-1)))<<1; //这一步相当于把from向左推了一位,个位用0补齐
        int tmp=from^to; //tmp应该只有一个1
        if(tmp==(tmp&(-tmp))) return true; //tmp只有一个1,则是合法的
        return false; //否则是不合法的
    }
    
    int status[MAXN],top=0; //保存所有DP过程中可能出现的状态的栈
    
    int main()
    {
        scanf("%d%d%d",&n,&k,&p);
        for(int S=(1<<(p-1));S<(1<<p);S++) //枚举DP状态S,S是合法状态当且仅当S的二进制中1的个数恰好为k
        {
            if(calc(S)==k)
            {
                status[++top]=S;
                if(S==(1<<p)-1-((1<<(p-k))-1)) goal=top; //S是最终要达到的状态
            }
        }
        for(int i=1;i<=top;i++)
            for(int j=1;j<=top;j++)
                if(canConvert(status[i],status[j]))
                    T.num[i][j]=1;
        A.n=A.m=T.n=T.m=top;
        A.num[1][goal]=1;
        T=fastPow(T,n-k);
        A=A*T;
        printf("%d
    ",A.num[1][goal]);
        return 0;
    }
    View Code
  • 相关阅读:
    Oracle DataGuard搭建(二)
    Oracle DataGuard搭建(一)
    Linux 安装oracle10g 配置dataguard 介绍和步骤
    Oracle DataGuard数据备份方案详解
    汽车行业的DMS系统 IT不变应万变
    汽车行业DMS系统介绍
    详解UML中的聚合,关联,泛化等关系
    ASP.NET将Session保存到数据库中
    C#快捷键
    Asp.net中使用资源文件实现网站多语言
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6882236.html
Copyright © 2020-2023  润新知