蓝桥杯 - 完美的代价(贪心+模拟)
回文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。小龍龍認為回文串才是完美的。現在給你一個串,它不一定是回文的,請你計算最少的交換次數使得該串變成一個完美的回文串。
交換的定義是:交換兩個相鄰的字符
例如mamad
第一次交換 ad : mamda
第二次交換 md : madma
第三次交換 ma : madam (回文!完美!)
輸入格式:
第一行是一個整數N,表示接下來的字符串的長度(N <= 8000)
第二行是一個字符串,長度為N.只包含小寫字母
輸出格式:
如果可能,輸出最少的交換次數。
否則輸出Impossible
輸入樣例:
5 mamad輸出樣例:
3這個題一開始是一點思路都沒有,后來聽了zx學長的證明后,就豁然開朗了,變成了一個簡單模擬題,證明的話我不太會,光說結論吧:
假如有個回文串是這樣的:
AXXXXXAXX?
有一段字符串為上圖所示,我們現在需要匹配字母A,無論怎么匹配,步數都是2
我們可以這樣想,在上面的字符串中,紅色的X代表中間對稱點,那么將兩個A分別對稱過去,出現了兩個橙色的X,若想完成匹配,我們可以有好多種方案:
所以說交換兩次,是讓字母A達到匹配的最優步數,若出現更多的交換次數,則一定不是最優解
有了以上結論后,我們還需要處理的一個問題是,若A已經完成匹配后,若后續再有字母在移動的過程中涉及到了已經完成匹配的字母A,字母A的位置也會發生變化,這時候該怎么處理呢?
這個問題就比較簡單了,可以從兩端開始處理,每處理完最外層的字母后,將區間向里收縮,再重復上述步驟進行匹配即可,這樣可以保證我們的操作無后效性,即不會影響前面的所有操作
還有一個小細節,就是如何判斷能否通過上述操作最后形成回文串,其實我們在一開始記錄一下每個字母出現的次數,必須保證奇數次字母最多有1個,否則肯定無法組成回文串,那么現在問題來了,我們又可以分兩種情況來討論:
第一種情況很簡單,就是上述討論的情況,針對第二種情況,顯而易見該字符串的長度一定是奇數,并且組成的回文串最中間一定是該字母,這樣一來,我們在處理的時候,有兩種方法
然后就上代碼了,兩份代碼都能A:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #define Pi acos(-1.0) using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100; int n;string s;int cnt[30];int cal(char ch) {int ans=0;for(int i=0;i<n/2;i++){if(s[i]==ch)//若遇到奇數次字母{if(cnt[ch-'a']==1)//若奇數次字母落單了{reverse(s.begin(),s.end());//翻轉字符串i--;//記得讓光標回溯一個單位continue;//然后繼續處理即可}else//沒落單的話,實時更新還剩多少個字母cnt[ch-'a']-=2;}int cnt=0;for(int j=n-i-1;j>i;j--){if(s[i]==s[j]){ans+=cnt;while(cnt)//小模擬{swap(s[n-i-1-cnt],s[n-i-1-cnt+1]);cnt--;} break;}cnt++;}}return ans; }int main() { // freopen("input.txt","r",stdin);cin>>n>>s;for(int i=0;i<n;i++)cnt[s[i]-'a']++;int num=0;char ch='A';for(int i=0;i<26;i++)if(cnt[i]&1){num++;ch='a'+i;}if(num>1)printf("Impossible\n");else{printf("%d\n",cal(ch));}return 0; } #include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #define Pi acos(-1.0) using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100; int n;string s;int cnt[30];int cal() {int ans=0;//剩余字母的貢獻int ans2=0;//落單字母的貢獻int temp=n;for(int i=0;i<n/2;i++){int j;int cnt=0;for(j=temp-1;j>i;j--){if(s[i]==s[j]){ ans+=cnt;while(cnt){swap(s[temp-1-cnt],s[temp-1-cnt+1]);cnt--;}temp--; break;}cnt++;}if(i==j)//若當前字母沒有找到匹配的對象,則說明該字母為落單字母ans2=(n-1)/2-i;//計算落單字母的貢獻,計算完貢獻后并不會將其模擬到中間點,而是將其直接忽略,避免重復計算}return ans+ans2; }int main() { // freopen("input.txt","r",stdin);cin>>n>>s;for(int i=0;i<n;i++)cnt[s[i]-'a']++;int num=0;for(int i=0;i<26;i++)if(cnt[i]&1)num++;if(num>1)printf("Impossible\n");else{printf("%d\n",cal());}return 0; }?
總結
以上是生活随笔為你收集整理的蓝桥杯 - 完美的代价(贪心+模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU - 1847 Good Luck
- 下一篇: CodeForces - 555A Ca