CF1383C String Transformation 2
一、题目
点此看题
感觉其他人的题解都不是很清楚,包括后来那个人的证明也是一样。
但是看不懂我的题解也别喷我,我不一定理解对了
二、解法
首先把转图论模型:有
记
Lamma:
首先证明可以构造到这个答案,考虑把
除了
然后证明它是答案下界,我们考虑
- 如果加入的边
(u,v) 对应G_2 中的两个弱联通块,那么合并这两个弱联通块,弱联通块个数减1 - 如果加入的边
(u,v) 在同一个弱联通内,最坏情况下会使T 中某个点存在时间递增的走回自己的路径,我们可以从T 中去掉v 来保持原有的性质,此时T 的大小至多减1
考虑最优连边方案
那么现在的问题是求一个最大导出子图使其为
三、总结
建立图论模型需要积累各种量的意义,本题路径的意义表示一种转化方式。
证明答案下界的思路也很重要,本题用到的方法我称之为势能法,也就是我们找到某个量为势能,对于任意一种决策方案,考虑最坏情况让势能的减少量,根据这个东西来列不等式。
最后反过来思考,为什么本题会有和
#include <cstdio>
#include <iostream>
using namespace std;
const int M = 100005;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int T,n,ans,mx,fa[20],out[20],dp[1<<20];
char s[M],t[M];
int find(int x)
{
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
void work()
{
n=read();scanf("%s%s",s,t);ans=mx=0;
for(int i=0;i<20;i++) fa[i]=i,out[i]=0;
for(int i=0;i<(1<<20);i++) dp[i]=0;
for(int i=0;i<n;i++)
{
int x=s[i]-'a',y=t[i]-'a';
out[x]|=(1<<y);
fa[find(x)]=find(y);
}
ans=40;dp[0]=1;
for(int i=0;i<20;i++)
if(i==find(i)) ans--;
for(int i=0;i<(1<<20);i++) if(dp[i])
{
mx=max(mx,__builtin_popcount(i));
for(int j=0;j<20;j++)
if(!(i&(1<<j)) && (out[j]&i)==0)
dp[i|(1<<j)]=1;
}
printf("%d\n",ans-mx);
}
signed main()
{
T=read();
while(T--) work();
}