bzoj 1009&&1875[矩阵优化dp]

贴代码…题解有空来打

//bzoj 1875
#include<cstdio>
#include<cstring>
#define P 45989
using namespace std;

struct edge{int from,to,next;}e[130];
int n,m,t,A,B,cnt,ans,head[25];

struct Matrix
{
    int v[125][125];
    Matrix(){memset(v,0,sizeof(v));}
    friend void print(Matrix a)
    {
        for(int i=0;i<=cnt;++i)
            for(int j=0;j<=cnt;++j) printf("%d%s",a.v[i][j],j==cnt?"\n":" ");
    }
    friend Matrix operator * (Matrix a,Matrix b)
    {
        Matrix res;
        for(int i=0;i<=cnt;++i)
            for(int j=0;j<=cnt;++j)
            {
                res.v[i][j]=0;
                for(int k=0;k<=cnt;++k)
                    (res.v[i][j]+=a.v[i][k]*b.v[k][j]%P)%=P;
            }
        return res;
    }
    friend Matrix operator ^ (Matrix a,int b)
    {
        Matrix ans;
        for(int i=0;i<=cnt;++i)  ans.v[i][i]=1;
        while(b)
        {
            if(b&1) ans=ans*a;
            b>>=1;a=a*a;
        }
        return ans;
    }
}a,b;

void insert(int x,int y)
{
    e[++cnt].next=head[x],e[cnt].from=x,e[cnt].to=y,head[x]=cnt;
    e[++cnt].next=head[y],e[cnt].from=y,e[cnt].to=x,head[y]=cnt;
}

int main()
{
    scanf("%d %d %d %d %d",&n,&m,&t,&A,&B);
    int i,j,x,y;
    memset(head,-1,sizeof(head));
    for(i=1,cnt=-1;i<=m;++i)
    {
        scanf("%d %d",&x,&y);
        insert(x,y);
    }
    for(i=head[A];i!=-1;i=e[i].next) ++a.v[1][i];
    for(i=0;i<=cnt;++i)
        for(j=0;j<=cnt;++j)
            if(e[i].to==e[j].from&&i!=(j^1)) ++b.v[i][j];
    a=a*(b^(t-1));
    for(i=head[B];i!=-1;i=e[i].next)
        (ans+=a.v[1][i^1])%=P;
    printf("%d\n",ans);
}
//bzoj 1009
#include<cstdio>
#include<cstring>
#define N 20
using namespace std;

int n,m,P,nxt[N+5];
char s[N+5];

struct Matrix
{
    int v[N+5][N+5],n,m;
    void clear(int x,int y){n=x,m=y;memset(v,0,sizeof(v));return;}
    friend Matrix operator * (Matrix a,Matrix b)
    {
        Matrix res;res.clear(a.n,b.m);
        for(int i=0;i<=a.n;++i)
            for(int j=0;j<=b.m;++j)
                for(int k=0;k<=a.m;++k)
                    (res.v[i][j]+=a.v[i][k]*b.v[k][j]%P)%=P;
        return res;
    }
    friend Matrix operator ^ (Matrix a,int k)
    {
        Matrix res;res.clear(a.n,a.n);
        for(int i=0;i<=a.n;++i) res.v[i][i]=1;
        while(k)
        {
            if(k&1) res=res*a;
            k>>=1;a=a*a;
        }
        return res;
    }
}a,ans;

int main()
{
    scanf("%d %d %d",&m,&n,&P);
    scanf("%s",s+1);
    int now=0;
    for(int i=2;i<=n;++i)
    {
        while(now&&s[now+1]!=s[i]) now=nxt[now];
        if(s[now+1]==s[i]) ++now;
        nxt[i]=now;
    }
    a.clear(n,n);
    for(int i=0;i<n;++i)
        for(int j=0;j<=9;++j)
        {
            now=i;
            while(now&&s[now+1]-'0'!=j) now=nxt[now];
            if(s[now+1]-'0'==j) ++now;
            if(now<n) a.v[i][now]=(a.v[i][now]+1)%P;
        }
    ans.clear(1,n),ans.v[0][0]=1,ans=ans*(a^m);
    int res=0;
    for(int i=0;i<n;++i) (res+=ans.v[0][i])%=P;
    printf("%d\n",res);return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值