E. String Reversal
给出一个长度为2e5的字符串s
要求只能通过交换相邻字母的操作将它变换成它的镜像字符
如aaaza ->azaaa
问最少要几次操作
首先从s变换成它的镜像t
例如abac ->caba
对于t串的第一个a 它一定从s串的第一个a移动得到
对于第t串的第二个a它一定从s串的第二个a移动得到
因为加入t串中第一个a用s串中第二个a ,第二个a用s串中第一个a
必定会导致在交换获得第二个a时会与前一个a交换位置 但这并不改变串的形态
所以这一步显然多余 为了避免这种情况发生 t串某个字母第几次出现 它就一定是
s串中第几次(从左到右遍历而言)出现的相同字母移动而来
实际上若不避免相同字母相邻互换操作产生的次数
任意一种s->t所需的交换次数是相同的
无论是规定s中第几个a变为t中第几个a,还是先让某个位置的a先移动到达目标位置
找完t中每个字母从s中哪一位字母移动得到后
我们可以得到一个位置下标的映射数组
如abac为[1,2,3,4] -> caba为[4,1,2,3]
那么这个问题就变成了将某个1到n的乱序排列 sort还原成1,2,3,4,5…n的排列
而最小交换相邻元素的次数实际上就是求逆序对个数
求逆序对科技很多 比如用权值线段树 并归排序 甚至字典树处理二进制位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <bits/stdc++.h> using namespace std; typedef long long ll; #define endl '\n' #define Turnoff std::ios::sync_with_stdio(false) #define P pair<ll,ll> const int Max=2e5+5; const int Mod=1e9+7; const int inf=0x3f3f3f3f;
class SegTree{ public: #define mid ((L+R)>>1) #define Leftson now<<1 #define Rightson now<<1|1 struct segtree{int L,R;ll sum;}; segtree tree[Max<<2]; void push_up(int now){ tree[now].sum=tree[Leftson].sum+tree[Rightson].sum; return; } void build(int L,int R,int now=1){ tree[now]={L,R,0}; if(L==R)return; build(L,mid,Leftson); build(mid+1,R,Rightson); push_up(now); return; } void updata(int pos,ll val,int now=1){ if(tree[now].L==tree[now].R){ tree[now].sum=tree[now].sum+val; return; } if(pos<=tree[Leftson].R)updata(pos,val,Leftson); if(pos>=tree[Rightson].L)updata(pos,val,Rightson); push_up(now);return; } ll query(int qL,int qR,int now=1){ if(qL>qR)return 0; if(tree[now].R<=qR&&tree[now].L>=qL)return tree[now].sum; ll sum=0; if(tree[Leftson].R>=qL)sum+=query(qL,qR,Leftson); if(tree[Rightson].L<=qR)sum+=query(qL,qR,Rightson); return sum; } }GetInv;
int to[Max]; int main(){ Turnoff; ll n,ans=0;cin>>n; string s,t;cin>>s; GetInv.build(1,n); t=s;reverse(t.begin(),t.end()); for(char x='a';x<='z';x++){ int pos=0; for(int i=0;i<n;i++){ if(t[i]!=x)continue; while(pos<n&&s[pos]!=x)pos++; if(pos==n)continue; to[i]=pos+1;pos++; } }
for(int i=0;i<n;i++){ ans+=GetInv.query(to[i]+1,n); GetInv.updata(to[i],1); } cout<<ans<<endl; }
|