题目链接:Codeforces - Deciphering
我们其实可以看成是字母直接的匹配,然后求一个最大权值的匹配。
怎么求对应的权值呢?显然我们只需要知道某个字母转化为另一个字母的价值,直接遍历一遍即可。
最后还需要输出对应的匹配,就是link数组,注意link[i]是匹配 i 的点,而不是 i 匹配的link[i],注意。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e3+10,M=1e6+10;
int n,k,res[N]; char a[M<<1],b[M<<1]; map<int,int> mp,rmp;
struct KM{
int w[N][N],lx[N],ly[N],visy[N],slack[N],pre[N],link[N];
int bfs(int k){
int x,y=0,yy=0,delta; memset(pre,0,sizeof pre);
for(int i=1;i<=n;i++) slack[i]=inf; link[y]=k;
while(1){
x=link[y],delta=inf,visy[y]=1;
for(int i=1;i<=n;i++){
if(!visy[i]){
if(slack[i]>lx[x]+ly[i]-w[x][i])
slack[i]=lx[x]+ly[i]-w[x][i],pre[i]=y;
if(slack[i]<delta) delta=slack[i],yy=i;
}
}
for(int i=0;i<=n;i++){
if(visy[i]) lx[link[i]]-=delta,ly[i]+=delta;
else slack[i]-=delta;
}
y=yy; if(link[y]==-1) break;
}
while(y) link[y]=link[pre[y]],y=pre[y];
}
int calc(){
memset(link,-1,sizeof link); int res=0;
for(int i=1;i<=n;i++) memset(visy,0,sizeof visy),bfs(i);
for(int i=1;i<=n;i++) if(link[i]) res+=w[link[i]][i];
return res;
}
}s;
signed main(){
cin>>n>>k; scanf("%s %s",a+1,b+1);
for(int i=1;i<=k;i++){
if('a'+i-1<='z') mp['a'+i-1]=i,rmp[i]='a'+i-1;
else mp['a'+i-2-'z'+'A']=i,rmp[i]='a'+i-2-'z'+'A';
}
for(int i=1;i<=n;i++) s.w[mp[a[i]]][mp[b[i]]]++; n=k;
cout<<s.calc()<<endl;
for(int i=1;i<=n;i++) res[s.link[i]]=i;
for(int i=1;i<=n;i++) printf("%c",rmp[res[i]]);
return 0;
}