【Codeforces 1430E】String Reversal | 逆序对、树状数组、思维

题目链接:https://codeforces.com/contest/665/problem/D

题目大意:

给出一个字符串s,将字符串s倒置后形成字符串t
每次可以对字符串s进行操作,每次可以交换相邻的两个字符
询问最少交换多少次可以使得s->t

题目思路:

备战CCPC刷题的时候的遗留问题
首先将字符串s倒置之后形成字符串t
交换操作首先考虑逆序对:
将一段序列进行冒泡排序,进行相邻交换,最后的交换次数最少为:逆序对总和
那么可以这么考虑这个题:
令最终状态 t 的每个位置成为最后的有序序列
abcde -> 12345
aabbb -> 12345
第一个例子来看,翻转之后成为54321,那么逆序对就是答案了
第二个例子来看,翻转之后成为54321,但此时逆序对并不是答案
,为什么呢?
因为,此时aa是可以不需要交换的,也就是说aa是同一个元素,不需要考虑谁前谁后。
所以,把同一个元素内部进行排序,即第二个例子反转后成为:45123
这样就可以了。

另外还有一种树状数组直接维护,当前位置前有几个数的写法,思路也比较容易懂,大概分两步:
1.记录每个字母的出现位置
2.每次让最近的字母移动到当前位置,过程用树状数组维护

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 4e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll num[maxn];
vector<int>v[30];
char s[maxn];
int c[maxn];
ll sum[maxn];
void add(int pos){
    
    
    while(pos<=n){
    
    
        sum[pos]++;
        pos += pos&-pos;
    }
}
ll GetSum(int pos){
    
    
    ll ans = 0;
    while(pos){
    
    
        ans += sum[pos];
        pos -= pos&-pos;
    }return ans;
}
int main(){
    
    
    ///11123
    ///32111
    read(n);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
        v[s[i]-'a'].push_back(i);
    for(int i=0;i<26;i++){
    
    
        int sz =v[i].size();
        for(int l = 0,r = sz-1;l<sz;l++,r--){
    
    
            int x = v[i][l];
            c[n-x+1] = v[i][r];
        }
    }
    ll ans = 0;
    for(int i=1;i<=n;i++){
    
    
        ans += GetSum(n)-GetSum(c[i]);
        add(c[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

/***
aaaza
azaaa
****/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111633708