【题解】外星物种的遗传物质

· · 个人记录

题面:

外星物种的遗传物质

在离太阳系很遥远的一个星球上,有一些奇特的物种,名为OIer

他们的遗传物质叫AC,类似于人类的DNA

AC也是链状的,但AC有头尾之分

组成AC的单体有26种,分别名为WA,TLE,RE,MLE,CE,PE,OLE,UKE......

为了方便表示,这里将这26中单体用26个小写字母表示

现在OIer们正在研究AC:

如何用最少的花费将一串AC变成另一串AC

现在OIer们有以下技术:

01:对于一串AC,可从尾部逐个删除单体,不需要任何花费

10:对于任何一个位置的单体,可以经过一些变化变成想要的单体,花费为所有变化的

总花费,变化规则OIer已经研究透了

11:对于一串AC,可以从尾部逐个添加任意一个单体,当在这串AC尾部第k次添加单体

时花费为k*c 现在给出m个变化规则,每个变化规则x,y,z表示x单体可花费z变成y单体

并有t对AC,每对AC中有两串长度至少为1的AC:s1,s2

对于每对AC,要求将s2变成s1最小花费是多少

又由于OIer超级喜欢二进制,所以最小花费均用二进制数输出

分析:

很明显我们需要知道任意一个单体x变成任意一个单体y的最小花费

这个就用多源最短路Floyd来处理,把各个单体看做结点共26个结点,然后跑一遍Floyd

然后再按两个字符串的长度分类

接着枚举位置,这个位置之前用“替换”,这个位置之后用“先删除后添加”

这样就能遍历所有情况了

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

long long m,t,c,e[27][27],q[10005];
char s1[10005],s2[10005];
long long cost(int x) {
    return (x*x+x)*c/2;//“先删除后添加”所需的花费,x是作用的单体数,返回的结果就是等差数列前x项和
}
int main() {
    scanf("%lld %lld %lld",&m,&t,&c);
    char x[2],y[2];
    long long z;
    for(int i=0; i<26; i++)
        for(int j=0; j<26; j++)
            e[i][j]=1e14;
    for(int i=0; i<26; i++)
        e[i][i]=0;//自己变自己不需要花费
    for(int i=1; i<=m; i++) {
        scanf("%s %s %lld",x,y,&z);
        e[x[0]-'a'][y[0]-'a']=min(e[x[0]-'a'][y[0]-'a'],z);
    }
    for(int k=0; k<26; k++)
        for(int i=0; i<26; i++)
            for(int j=0; j<26; j++)
                if(e[i][k]+e[k][j]<e[i][j])
                    e[i][j]=e[i][k]+e[k][j];
    long long ans,l,ls,a[64],ia;
    for(int i=1; i<=t; i++) {
        scanf("%s %s",s1,s2);
        l=min(strlen(s1),strlen(s2));
        ls=strlen(s1);
        if(ls>l) {
            ans=cost(ls);
            q[0]=e[s2[0]-'a'][s1[0]-'a'];
            for(int j=1; j<l; j++) {
                q[j]=q[j-1]+e[s2[j]-'a'][s1[j]-'a'];
                ans=min(ans,q[j-1]+cost(ls-j));
            }
            ans=min(ans,q[l-1]+cost(ls-l));
        } else {
            ans=cost(l);
            q[0]=e[s2[0]-'a'][s1[0]-'a'];
            for(int j=1; j<l; j++) {
                q[j]=q[j-1]+e[s2[j]-'a'][s1[j]-'a'];
                ans=min(ans,q[j-1]+cost(l-j));
            }
            ans=min(ans,q[l-1]);
        }
        ia=0;
        if(ans==0) putchar('0'); 
        while(ans) {
            a[ia++]=ans&1;
            ans>>=1;
        }
        for(int j=ia-1; j>=0; j--)
            putchar('0'+a[j]);
        putchar('\n');
    }
    return 0;
}