[关闭]
@xiaoziyao 2020-11-26T05:00:16.000000Z 字数 1421 阅读 900

AT3733 [ARC088C] Papple Sort解题报告

解题报告


AT3733 [ARC088C] Papple Sort解题报告:

更好的阅读体验

题意

分析

我们考虑每一个字符在最后的回文串里会与什么字符配对,发现从前往后第个字符一定会与从后往前第个字符匹配。(因为交叉式的匹配一定不优于或等价与包含式的匹配)

  1. 解释:
  2. c...c...c...c
  3. 第一个c与第四个c匹配一定比第一个c与第三个c匹配等价或更优

而确定了匹配的对象之后,我们不难发现对于两对匹配了的字符,不交换位置一定比交换位置优

  1. 解释:
  2. 假设匹配后是:c...b...b...c
  3. 如果交换成匹配b...c...c...b,也不会对其他的匹配有任何帮助,还不如不交换位置

这样我们就有了一个基本的思路:枚举每一个没有匹配过的字符,找到与它对应的字符,然后把这两个字符移动到最外侧的位置,这样就可以把这一对字符视为已删除。

考虑当前字符之前的所有字符已经进行过了操作,所以一定在最外侧,我们只需要把与它匹配的字符移动到末尾,我们只需要用一个树状数组维护当前的字符就好了。

对于单独的字符,我们标记一个flg,然后在之后的操作的费用都增加就好了(因为之后的匹配的左端点需要向左移动一次)。

代码

  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<vector>
  4. #define lowbit(x) x&-x
  5. using namespace std;
  6. const int maxn=200005,maxk=30;
  7. int all,flg,n,now;
  8. long long ans;
  9. int a[maxn],used[maxn],t[maxn];
  10. string s;
  11. vector<int>v[maxk];
  12. void update(int x,int v){
  13. for(int i=x;i<=n;i+=lowbit(i))
  14. t[i]+=v;
  15. }
  16. int query(int x){
  17. int res=0;
  18. for(int i=x;i;i-=lowbit(i))
  19. res+=t[i];
  20. return res;
  21. }
  22. int main(){
  23. cin>>s;
  24. n=s.size();
  25. for(int i=0;i<s.size();i++){
  26. a[i+1]=s[i]-96;
  27. v[s[i]-96].push_back(i+1);
  28. }
  29. for(int i=1;i<=26;i++)
  30. if(v[i].size()&1)
  31. all++;
  32. if(all>1){
  33. puts("-1");
  34. return 0;
  35. }
  36. for(int i=1;i<=n;i++)
  37. update(i,1),now++;
  38. for(int i=1;i<=n;i++){
  39. if(used[i])
  40. continue;
  41. int x=v[a[i]][v[a[i]].size()-1];
  42. if(x==i){
  43. v[a[i]].pop_back(),flg=1;
  44. used[i]=1,update(i,-1),now--;
  45. continue;
  46. }
  47. v[a[i]].pop_back();
  48. ans+=1ll*(now-query(x))+flg;
  49. used[i]=used[x]=1;
  50. update(i,-1),update(x,-1),now-=2;
  51. }
  52. printf("%lld\n",ans);
  53. return 0;
  54. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注