RT.
赛时 T1,T2 都尝试写正解,都 WA 了,Gold 无望。
以下来自我的游记
读了一遍题,发现原题面可以用一个有向图表示出来。
我认为一种字母变为另一种字母,就是建一条有向边。
如果某个点出度 $\ge 2$,或者所有连通子图都是环且所有字母都出现过,无解。
我手动模拟了一些数据,发现对于每个连通子图,如果是链,对答案的贡献为 size,如果是环,则还有破环为链的代价,贡献为 size+1。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int t;
char a[maxn],b[maxn];
map<char,char> to;
map<char,bool> ins;
map<char,int> siz;
map<char,bool> vis;
bool circle=0;
void dfs(char u)
{
if(vis[u])
{
siz[u]=0;
return;
}
vis[u]=1;
ins[u]=1;
if(to[u]&&to[u]!=u)
{
siz[u]=1;
if(ins[to[u]])
{
ins[u]=0;
circle=1;
return;
}
dfs(to[u]);
}
ins[u]=0;
siz[u]+=siz[to[u]];
}
int main()
{
scanf("%d",&t);
while(t--)
{
ins.clear();
to.clear();
siz.clear();
vis.clear();
scanf("%s",a+1);
scanf("%s",b+1);
int n=strlen(a+1);
assert(n==strlen(b+1));
bool imposs=0;
for(int i=1;i<=n;i++)
{
if(!to[a[i]])
{
to[a[i]]=b[i];
}
else if(to[a[i]])
{
if(to[a[i]]!=b[i])
{
imposs=1;
break;
}
}
}
if(imposs)
{
puts("-1");
continue;
}
bool hasd0=0;//存在可以变成空闲的点
for(char i='a';i<='z';i++)
{
circle=0;
dfs(i);
if(!circle)
{
hasd0=1;
break;
}
}
for(char i='A';i<='Z';i++)
{// 接着上一个循环枚举
circle=0;
dfs(i);
if(!circle)
{
hasd0=1;
break;
}
}
//==================
ins.clear();
siz.clear();
vis.clear();
int ans=0;
for(char i='a';i<='z';i++)
{
if(!to[i]||(i==to[i]||vis[i]))continue;
circle=0;
dfs(i);
if(!circle)
{
// printf("(1) char: %c added: %d\n",i,siz[i]);
ans+=siz[i];
}
else if(circle)
{
// printf("(2) char: %c added: %d\n",i,siz[i]+1);
ans+=siz[i]+1;
if(!hasd0)
{
imposs=1;
break;
}
}
}
for(char i='A';i<='Z';i++)
{// 接着上一个循环枚举
if(!to[i]||(i==to[i]||vis[i]))continue;
circle=0;
dfs(i);
if(!circle)
{
// printf("(1) char: %c added: %d\n",i,siz[i]);
ans+=siz[i];
}
else if(circle)
{
// printf("(2) char: %c added: %d\n",i,siz[i]+1);
ans+=siz[i]+1;
if(!hasd0)
{
imposs=1;
break;
}
}
}
if(imposs)puts("-1");
else printf("%d\n",ans);
}
return 0;
}