[NOIP模拟赛]字母选择问题

来源:互联网 发布:算法精解 epub 编辑:程序博客网 时间:2024/05/16 12:37
题目描述
输出仅包含小写英文字符的字符串S,支持以下一种操作:选择一个字母X,然后选定该字符串中所有的X,并用另一种小写英文字母Y替换它们,代价为被替换的字符的个数

例如,S=“goose”,本次操作所选的X=“o”且Y=“e”,操作结束后的S=“geese”,本次操作的代价为2。要求只用这种操作,使得该字符串变为回文串,同时使得代价之和最小。


输入格式

第1行:1个字符串S(1≤S。Size()≤10^5)


输出格式

第1行:1个整数,表示把S改为回文串的最小操作代价


输入样例

geese


输出样例

2


样例说明
第1次操作把g改为e,第2次操作把s改为e,字符串变成:“eeeee”,即为回文串。

 


题解
对称位置上的字符,若它们不相同,那么修改后必须相同。
由此建一个最多有26个点的图,每个点表示一个小写字母。若对称位置上的字符不相同,则将两个点连起来。最后会有一个或多个联通块,一个联通块中的字符必须相同。因此对于每个联通块,选择数量最多的字母,将其他字母全部变成这个字母,代价为其他字母数量之和。最后将所有联通块加起来就是答案。
建图可以直接建,也可以用并查集维护。这里选择直接建。


#include<cstring>#include<cstdio>#include<algorithm>using namespace std;const int N=1e5+5;int sum, cnt[30];bool map[30][30];char ch[N];int Num( char s ) { return s-'a'+1; }int fir[30], ecnt;struct node{ int e, next; } edge[2000];void Link( int s, int e ) {edge[++ecnt].e=e; edge[ecnt].next=fir[s]; fir[s]=ecnt;edge[++ecnt].e=s; edge[ecnt].next=fir[e]; fir[e]=ecnt;}int que[30];void BFS( int s ) {int l=1, r=0, maxv=0;que[++r]=s;maxv=max( maxv,cnt[s] );sum+=cnt[s]; cnt[s]=0;while( l<=r ) {s=que[l++];for( int i=fir[s]; i; i=edge[i].next )if( cnt[ edge[i].e ] ) {que[++r]=edge[i].e;maxv=max( maxv,cnt[ edge[i].e ] );sum+=cnt[ edge[i].e ]; cnt[ edge[i].e ]=0;}}sum-=maxv;}int main() {scanf( "%s", ch+1 );int len=strlen( ch+1 );for( int l=1, r=len; l<=r; l++, r-- ) {int c1=Num(ch[l]), c2=Num(ch[r]);cnt[c1]++; cnt[c2]++;if( l==r ) { cnt[c1]--; break; }if( ch[l]!=ch[r] && !map[c1][c2] )Link( c1, c2 ), map[c1][c2]=1;}for( int i=1; i<=26; i++ )if( cnt[i] ) BFS(i);printf( "%d\n", sum );return 0;}


原创粉丝点击