題目大意:有初始字符串和目標字符串,目標字符串是初始字符串的反轉。
每一步可交換相鄰兩個字符,求從初始字符串到目標字符串的最小步數。
題解:
若初始字符串爲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; }