題目描述
輸出僅包含小寫英文字符的字符串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; }
[NOIP模擬賽]字母選擇問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.