返回顶部

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;
    }
    
posted @ 2020-11-06 10:24  Rayotaku  阅读(66)  评论(0编辑  收藏  举报