• 【Luogu】P3758可乐(矩阵优化DP)


      题目链接

      一开始想到这可能能用矩阵优化,但以为暴力就能卡过……T成二十分

      首先我们回顾一下我们的暴力转移方程

      用f[i][j][0/1]表示在i时刻,j点,1不爆炸,0已爆炸的方案数,那么f[i][j][0]=f[i-1][j][0]+f[i-1][j][1],f[i][j][1]=f[i-1][j][1]+f[i-1][k][1](其中k表示与j相邻的点)。

      然后我们看f[i][j][1]=f[i-1][j][1]+f[i-1][k][1]这个式子

      如果设定j和j相连,就化简为f[i][j][1]=f[i-1][k][1]

      然后就可以用矩阵乘法啦

      考虑到f[i][j][0]的求法,发现这是一个关于f[i-1][j][1]的和

      而我们发现f[i-1][j][1]是一串矩阵等比数列

      于是应用等比数列求和公式

      

    #include<algorithm>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #define mod 2017
    
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    int n,m;
    
    struct Matrix{
        long long s[32][32];
        Matrix(){memset(s,0,sizeof(s));    }
        Matrix operator *(const Matrix &a){
            Matrix ans;
            for(int i=1;i<=n;++i)
                for(int j=1;j<=n;++j)
                    for(int k=1;k<=n;++k)
                        ans.s[i][j]=(ans.s[i][j]+(s[i][k]*a.s[k][j])%mod)%mod;
            return ans;
        }
        Matrix operator +(const Matrix &a){
            Matrix ans;
            for(int i=1;i<=n;++i)
                for(int j=1;j<=n;++j)
                    ans.s[i][j]=(s[i][j]+a.s[i][j])%mod;
            return ans;
        }
    };
    
    Matrix Pow(Matrix x,int p){
        Matrix ans;
        for(int i=1;i<=n;++i)    ans.s[i][i]=1;
        while(p){
            if(p&1)    ans=ans*x;
            x=x*x;
            p>>=1;
        }
        return ans;
    }
    
    Matrix Sum(Matrix x,int p){
        Matrix ans;
        if(!p)    return ans;
        for(int i=1;i<=n;++i)    ans.s[i][i]=1;
        ans=ans+Pow(x,p>>1);    ans=ans*Sum(x,p>>1);
        if(p&1)    ans=ans+Pow(x,p);
        return ans;
    }
    
    int q[300][300];
    Matrix Start;
    int ans;
    
    int main(){
        n=read(),m=read();
        for(int i=1;i<=m;++i){
            int from=read(),to=read();
            q[from][to]=q[to][from]=1;
        }
        for(int i=1;i<=n;++i)    q[i][i]=1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)    Start.s[i][j]=q[i][j];
        int t=read();
        Matrix now;    now=Pow(Start,t);
        for(int i=1;i<=n;++i)    ans=(ans+now.s[i][1])%mod;
        Matrix sum;    sum=Sum(Start,t -1);
        for(int i=1;i<=n;++i)    sum.s[i][i]=(sum.s[i][i]+1)%mod;
        for(int i=1;i<=n;++i)    ans=(ans+sum.s[i][1])%mod;
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Flex验证器 validate stringvalidate
    Flex4学习笔记 checkBox RadioButton DropDownList colorPicker
    Flex学习笔记PopUpMenuButton
    FLEX中一组基于button的组件
    flex学习笔记 显示数字步进
    flex学习笔记-日历选择与显示
    bar
    Flex的一些小实例
    最长公共子序列(LCS) Medium2
    最长公共子序列(LCS) Medium1
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/8052514.html
Copyright © 2020-2023  润新知