Educational Codeforces Round 96 (Rated for Div. 2) E. String Reversal (思维,逆序对)
-
题意:给你一个字符串,每次可以调换现字符串的相邻两个字符,问最少操作多少次使得这个字符串等于其反转过来的字符串.
-
题解:先考虑字符串中没有相同字符的情况,那么我们每次将目前字符串的最后一个字符一直调换到前面就行,如果出现相同字符的话,先让最靠前的字符调换到对应位置一定是最优的.我们先记录原字符串中每个字符的位置,然后将字符串反转,根据反转后的字符位置弄一个新数组,注意相同字符一定要把小的位置放在前面,然后用树状数组求个逆序对即可.
-
代码:
#define int long long int n; string s; vector<int> v[N]; int rev[N]; int cnt[N]; int c[N]; int lowbit(int x){ return x&(-x); } void update(int i,int k){ while(i<=n){ c[i]+=k; i+=lowbit(i); } } int get_sum(int i){ int res=0; while(i){ res+=c[i]; i-=lowbit(i); } return res; } signed main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n; cin>>s; s=" "+s; s+=" "; for(int i=1;i<=n;++i){ v[s[i]-'0'].pb(i); } reverse(s.begin(),s.end()); for(int i=1;i<=n;++i){ rev[i]=v[s[i]-'0'][cnt[s[i]-'0']++]; } int ans=0; for(int i=1;i<=n;++i){ update(rev[i],1); ans+=i-get_sum(rev[i]); } cout<<ans<<'\n'; return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮