日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

蓝桥杯 - 完美的代价(贪心+模拟)

發布時間:2024/4/11 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥杯 - 完美的代价(贪心+模拟) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

回文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。小龍龍認為回文串才是完美的。現在給你一個串,它不一定是回文的,請你計算最少的交換次數使得該串變成一個完美的回文串。

交換的定義是:交換兩個相鄰的字符

例如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向右交換一次
  • 所以說交換兩次,是讓字母A達到匹配的最優步數,若出現更多的交換次數,則一定不是最優解

    有了以上結論后,我們還需要處理的一個問題是,若A已經完成匹配后,若后續再有字母在移動的過程中涉及到了已經完成匹配的字母A,字母A的位置也會發生變化,這時候該怎么處理呢?

    這個問題就比較簡單了,可以從兩端開始處理,每處理完最外層的字母后,將區間向里收縮,再重復上述步驟進行匹配即可,這樣可以保證我們的操作無后效性,即不會影響前面的所有操作

    還有一個小細節,就是如何判斷能否通過上述操作最后形成回文串,其實我們在一開始記錄一下每個字母出現的次數,必須保證奇數次字母最多有1個,否則肯定無法組成回文串,那么現在問題來了,我們又可以分兩種情況來討論:

  • 若回文串中沒有奇數次的字母
  • 若回文串中有奇數次的字母
  • 第一種情況很簡單,就是上述討論的情況,針對第二種情況,顯而易見該字符串的長度一定是奇數,并且組成的回文串最中間一定是該字母,這樣一來,我們在處理的時候,有兩種方法

  • 忽略掉這個落單的字母不管,因為最后若所有的字母都處理完畢后,該字母一定會回到最中間的位置上,所以其貢獻的步數為0
  • 特殊處理這個落單的字母,單獨計算其貢獻,為了防止在后續會重復計算,我們在處理完該字母之后,不予模擬,也就是說計算完貢獻后假裝將其刪除
  • 然后就上代碼了,兩份代碼都能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; }

    ?

    總結

    以上是生活随笔為你收集整理的蓝桥杯 - 完美的代价(贪心+模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。