1. 程式人生 > 其它 >Codeforces Round 96 (Rated for Div. 2)E. String Reversal(樹狀陣列求逆序對)

Codeforces Round 96 (Rated for Div. 2)E. String Reversal(樹狀陣列求逆序對)

傳送門

題目大意:有初始字串和目標字串,目標字串是初始字串的反轉。

每一步可交換相鄰兩個字元,求從初始字串到目標字串的最小步數。

題解:

若初始字串為abcde,則反轉後為edcba。用陣列下標表示為初始字串12345,反轉後為54321。

反轉後的串的逆序對個數就是從初始串到目標串需要交換的相鄰字元的個數。

關鍵是如果初始字串中有重複,如aaaza,反轉後為azaaa。

用陣列下標表示為12345,反轉後為14235更優。

14235的逆序對個數就是12345交換相鄰元素的步數。

樹狀陣列求逆序對

寫題解時突聞吹風機被導員收走的噩耗

#include<iostream>
#include
<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define N 200002 int n; char s[N]; char t[N]; int c[N]; int tr[N]; long long res; queue<int>a[30]; int lowbit(int x) { return x&(-x); } void add(int x,int v) { for(int i=x;i<=n;i+=lowbit(i)) { tr[i]
+=v; } } int getsum(int x) { int tmp=0; for(int i=x;i>=1;i-=lowbit(i)) { tmp+=tr[i]; } return tmp; } int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;i++) { t[i]=s[n-i+1]; a[s[i]-'a'+1].push(i); } for(int
i=1;i<=n;i++) { c[i]=a[t[i]-'a'+1].front(); a[t[i]-'a'+1].pop(); } // for(int i=1;i<=n;i++) // cout<<c[i]<<" "; // cout<<endl; for(int i=1;i<=n;i++) { add(c[i],1); // cout<<getsum(c[i])<<":"; res=res+i-getsum(c[i]); } cout<<res; return 0; }