Description
一个字符串的变形词是一个字符串,它含有恰好完全一样的字母,可能以不同的顺序出现。例如,\porter",\report"和\eoprrt"都是\porter"的变形词。而\potter"不是它的变形词,因为\t"和\r"出现的次数不同。
字符串S和T是正交的,当且仅当它们长度相同,而且每个对应位都不同。例如,\card"和\dear"是正交的,而\perk"和\card"不是正交的,因为它们的第3个字母相同。
给出一个字符串S,求S的字典序最小的正交变形词。如果这样的字符串不存在,就让答案是空串。
Solution
早上想了一个正解贪心结果不会证明不太敢写。。
我们从小到大枚举当前位置填上的字符,后面是否能填用网络流判断。原点向字符连边容量为可用数量,每个字符向能放的位置连边容量为1,位置向汇点连边容量为1,那么剩余能放完当且仅当满流。我们把容量为x的边拆成x条容量为1的边,那么就变成存在完美匹配了
我们只需要证明最劣情况下它是合法的。对于不同的两个字符,它们连出去的边覆盖的点集一定是全集。对于相同的若干字符,它们连出去的边覆盖的点集不变,因此我们只需要比较每类字符能放的位置/剩余的数量即可。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
const int N=200005;
char s[N],t[N];
int a[26],b[26],c[26];
int main(void) {
scanf("%s",s+1); int n=strlen(s+1);
rep(i,1,n) a[s[i]-'a']++,b[s[i]-'a']++;
rep(i,'a','z') {
rep(j,'a','z') if (i!=j) {
c[i-'a']+=a[j-'a'];
}
}
rep(i,1,n) {
t[i]=1;
rep(j,'a','z') if (j!=s[i]&&a[j-'a']) {
a[j-'a']--;
rep(k,'a','z') if (s[i]!=k) c[k-'a']--;
bool flag=true;
rep(k,'a','z') if (a[k-'a']>c[k-'a']) flag=false;
if (flag) {
t[i]=j;
break;
}
a[j-'a']++;
rep(k,'a','z') if (s[i]!=k) c[k-'a']++;
}
if (t[i]==1) {
puts("");
return 0;
}
}
rep(i,1,n) putchar(t[i]); puts("");
return 0;
}