[矩阵快速幂 优化DP] 51Nod 1311 转换机

来源:互联网 发布:overlay sdn网络分为 编辑:程序博客网 时间:2024/05/23 00:09

题目梗概

给出一个初始字符串S和目标字符串T,仅包含a,b,c三种字母。

给出三种操作:

1)将字符串S中的一个‘a’字符变成‘b’,并消耗cost0的花费;

2)将字符串S中的一个‘b’字符变成‘c’,并消耗cost1的花费;

3)将字符串S中的一个‘c’字符变成‘a’,并消耗cost2的花费;

在总花费不超过M的限制下,求有多少种方案将S转化为T。

(|S|<=11,M<=1e9)

解题思路

将S转化为T的最小花费我们是可以很快求出的。

接下来就是将每一为的数字做无聊的循环操作,且花费固定的为cost1+cost2+cost3。

于是我们可以求出最大步数=最小步数+(M-最小花费)/(cost1+cost2+cost3)。

之后我们有了一个naive的思路:f[i][j]表示第i步时,字符串的状态为j,但是这样还是会超时。

可以发现如果要将S转化为T,每个位置操作次数mod 3的值是一定的,并且每个位置相对独立。

于是我们用f[i][j][k][t]表示第i步,%3=0的个数,%3=1的个数,%3=2的个数。

不难发现转移关系确定,直接矩乘优化。

#include<cstdio>#include<cstring>#define LL long longusing namespace std;const int maxn=15,tt=1000000007;const int num[3][3]={0,1,3,6,0,2,4,5,0};const int sum[3][3]={0,1,2,2,0,1,1,2,0};struct jz{    int n,m;    LL x[105][105];}A;char S[maxn],T[maxn];int c[3],h[3],hash[105][105],tot,MAXc,len;LL MINc,MAXs,MINs;jz cheng(jz a,jz b){    jz c;memset(c.x,0,sizeof(c.x));    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.x[i][j]+=(long long)a.x[i][k]*b.x[k][j]%tt)%=tt;    return c;}jz qsm(jz w,int b){    jz c;c.n=c.m=tot+1;    for (int i=1;i<=c.n;i++)    for (int j=1;j<=c.m;j++) c.x[i][j]=(i==j);    while(b>0){        if (b%2==1) c=cheng(c,w);        w=cheng(w,w);        b=b>>1;    }    return c;}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    scanf("%s",S+1);scanf("%s",T+1);    scanf("%d%d%d",&c[0],&c[1],&c[2]);    scanf("%lld",&MAXc);    len=strlen(S+1);    for (int j=1;j<=len;j++){        int x=num[S[j]-'a'][T[j]-'a'];        for (int i=2;i>=0;i--)        if (x>=(1<<i)) MINc+=c[i],x-=(1<<i);        h[sum[S[j]-'a'][T[j]-'a']]++;        MINs+=sum[S[j]-'a'][T[j]-'a'];    }    if (MAXc<MINc) return printf("0\n"),0;     MAXs=MINs+(MAXc-MINc)/(c[0]+c[1]+c[2])*3;    for (int i=0;i<=len;i++)    for (int j=0;i+j<=len;j++)    hash[i][j]=++tot;    for (int i=0;i<=len;i++)    for (int j=0;i+j<=len;j++){        if (i) A.x[hash[i-1][j]][hash[i][j]]=i;        if (j) A.x[hash[i+1][j-1]][hash[i][j]]=j;        A.x[hash[i][j+1]][hash[i][j]]=len-i-j;    }    A.n=tot+1;A.m=tot+1;A.x[tot+1][hash[len][0]]=A.x[tot+1][tot+1]=1;    A=qsm(A,MAXs+1);    printf("%lld\n",A.x[tot+1][hash[h[0]][h[1]]]);    return 0;}
原创粉丝点击