【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;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8052514.html