CF1526 D. Kill Anton
生活随笔
收集整理的這篇文章主要介紹了
CF1526 D. Kill Anton
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
CF1526 D. Kill Anton
題意:
給你一個由’A’,‘N’.‘T’,'O’四個字符組成的字符串b,現在要求你改變b的順序得到a,使得a通過移動回到b的步數最多。
每次移動只能移動相鄰兩項
題解:
官方題解說:最佳情況為相同字符靠在一起
證明我也不清楚。。
證明可以看看這篇文章
按照官方題解的說法,將相同的字符排列在一起,一共就四種字符,那么也就是排列方式一共就24種(4!),我們直接暴力求出每種情況,然后求出其要移動的步數,取最大值
這個移動的步數咋求?
假設原先字符串是ANTON,下標依次是1,2,3,4,5,現在我們將其打亂成ATONN,原先的下標就成了1,3,4,2,5,那13425變回12345的步驟不就是其逆序對嗎?所以對于每一種情況我們求其逆序對,然后保留最大值
這題挺好~
代碼:
#include <bits/stdc++.h> #define ll long long using namespace std; int a[50];//記錄字符個數 vector<int>id[50],c;//記錄字符 string s;ll nxt; void msort(int l,int r){//歸并排序 if(l>=r)return;//區間元素小于1 int mid=l+r>>1;msort(l,mid);//分 msort(mid+1,r);//分 int i=l,j=mid+1,k=0;int t[r-l+1];while(i<=mid&&j<=r){if(c[i]<=c[j])t[k++]=c[i++]; else{//此時存在逆序對,在歸并過程中記錄逆序對的個數 t[k++]=c[j++];nxt+=mid-i+1;//記錄逆序對數 }}while(i<=mid)t[k++]=c[i++];while(j<=r)t[k++]=c[j++];for(i=l,k=0;i<=r;i++,k++)c[i]=t[k];//將t排好序的數復制到c中 } int main() {ios_base::sync_with_stdio(false);int t;cin>>t;while(t--){int r[5]={0,'A','N','O','T'};//通過函數枚舉各種可能性; memset(a,0,sizeof(a));//清空 id['A'-'A'].clear();id['N'-'A'].clear();id['O'-'A'].clear();id['T'-'A'].clear();cin>>s;for(int i=0;i<s.size();i++){a[s[i]-'A']++;//記錄每個字母的個數 id[s[i]-'A'].push_back(i+1); }ll ans=0;string as;do{c.clear();nxt=0;//清零記錄下一種情況的操作數for(int i=1;i<=4;i++){//四個字符分別連續存入形成一個新的字符串 c.insert(c.end(),id[r[i]-'A'].begin(),id[r[i]-'A'].end());}/*cout<<"c= ";for(int i=0;i<c.size();i++)cout<<s[c[i]-1];cout<<endl; */msort(0,c.size()-1);if(nxt>ans){ans=nxt;as="";for(int i=1;i<=4;i++) as+=string(a[r[i]-'A'],(char)r[i]);//存入此時的最優字符串,即前面c的原串 }}while(next_permutation(r+1,r+5));//對四個字符全排列的各種可能性; if(ans!=0)cout<<as<<endl;else cout<<s<<endl;//ans為0說明原字符串已經為最優解 } return 0; }我還有看到一種寫法,本質一樣,它將轉化后的字符串下標定為1,2,3,4…,根據這個將原字符串下標定義為nxt[j],然后跑逆序對,一樣的
for(int i=0;i<len;i++){//將該情況的字符串轉為數字 for(int j=0;j<=3;j++){if(mp[s[i]]==nxt[j]){//每次打亂nxt c[i]=j;break;}}} #include<bits/stdc++.h> #define debug(a,b) printf("%s = %d\n",a,b); typedef long long ll; using namespace std; //qdu打鐵匠 inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w; } const int maxn=2e5+9; int nxt[]={0,1,2,3}; ll a[maxn]; ll c[maxn],b[maxn]; map<char,int>mp; ll cnt=0; void unite(int l,int mid,int r){if(l>=r)return ;unite(l,(l+mid)>>1,mid);unite(mid+1,(mid+1+r)>>1,r);int i=l,j=mid+1;for(ll k=l;k<=r;++k){if(j>r||i<=mid&&c[i]<=c[j]) b[k]=c[i++];else b[k]=c[j++],cnt+=mid-i+1;}for(ll k=l;k<=r;++k) c[k]=b[k]; } string s; ll cal(int len){for(int i=0;i<len;i++){//將該情況的字符串轉為數字 for(int j=0;j<=3;j++){if(mp[s[i]]==nxt[j]){//每次打亂nxt c[i]=j;break;}}}cnt=0;unite(0,(len-1)>>1,len-1);//求逆序對 return cnt; } void solve(){cin>>s;string a,n,o,t;for(int i=0;i<s.length();i++){if(s[i]=='A')a+='A';if(s[i]=='N')n+='N'; if(s[i]=='O')o+='O';if(s[i]=='T')t+='T';}string ans=s;ll sum=0;do{ll now=cal(s.size());if(now>sum){//得到更大的逆序對,即需要步數更多 sum=now;ans.clear();for(int i=0;i<=3;i++){if(nxt[i]==0)ans+=a;if(nxt[i]==1)ans+=n;if(nxt[i]==2)ans+=t;if(nxt[i]==3)ans+=o;} }}while(next_permutation(nxt,nxt+1+3));cout<<ans<<endl; } int main() {int t=read();mp['A']=0;mp['N']=1;mp['T']=2;mp['O']=3;while(t--){solve();} }總結
以上是生活随笔為你收集整理的CF1526 D. Kill Anton的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果 Mac 好搭档:戴尔 27 寸 4
- 下一篇: Take-Two 首席执行官:《GTA》