2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)

https://www.luogu.com.cn/problem/P5041

题意:

给一个字符串 \(S\) ,每次交换相邻两个位置的字符,使得 \(S\) 变成回文串,求最小交换次数。

分析:

首先,对于一个回文串,最多有一个字符出现次数为奇数,这个字符必须放在回文串的最中间,剩下的字符两边放就行。

对于一个字符 \(x\) ,一共在回文串中出现了 \(sizei_x\) 次,每次出现的位置为 \(pos_{x_i}\) 。这 \(sizei_x\) 个字符分布在中间字符(也可能没有中间字符,如果这个字符串长度为偶数)两侧,可想而知,每次移动最左边和最右边的两个字符把它们固定在对称的位置上是最优的,不然就像蓝书第一题,两只蚂蚁来回掉头就是两只蚂蚁一直前进一样。

好吧,假设一下,设字符 \(x\) 一共有4个,分别在 \(pos_{x_1}\) 、 \(pos_{x_2}\) 、 \(pos_{x_3}\) 、 \(pos_{x_4}\) ,且 \(pos_{x_1}<pos_{x_2}<pos_{x_3}<pos_{x_4}\) ,它们可以被固定在两个轴对称的位置 \(a\) 与 \(\alpha\) 、 \(b\) 与 \(\beta\) ,且 \(a<b<\beta<\alpha\) 。如果把 \(pos_{x_2}\) 与 \(pos_{x_3}\) 这两个位置上的 \(x\) 固定到 \(a\) 与 \(\alpha\) ,那么 \(pos_{x_2}\) 上的 \(x\) 一定会和 \(pos_{x_1}\) 上的交换,不如直接从 \(pos_{x_1}\) 开始交换,对于 \(pos_{x_3}\) 上的 \(x\) 同理。

对于两个相邻位置上的字符 \(x\) 与 \(y\) , \(x\) 在 \(y\) 的左边。如果离 \(x\) 最远的另一个相同的字符包含了离 \(y\) 最远的另一个相同字符,即 xyyx ,那么先选 \(x\) 再选 \(y\) 是最优的。如果两个字符交叉出现即 xyxy ,对结果并没有影响。如果两个字符分别重复出现即 xxyy ,对结果依旧没影响。所以按照顺序对字符进行排序最优。

至于一个字符究竟交换了几次?咱把原位置在排完序后的出现次序记录下来,求个逆序对~

树状数组,你值得拥有~

(咱是不是做过同类型的题?/疑惑)

代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#define IOS ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std; #define int long long
const int N=1e6+10;
int n,a[N],fin[N],t[N],vis[N],top[N],len;
vector<int>pos[30]; inline int lowbit(int x){
return x&-x;
}
inline void add(int x,int k){
for(int i=x;i<=n+5;i+=lowbit(i))t[i]+=k;
}
inline int query(int x){
int ans=0;
for(int i=x;i>0;i-=lowbit(i))ans+=t[i];
return ans;
} signed main(){
IOS;
string s;cin>>s;
n=s.length();
int cnt=0;
for(int i=1;i<=n;i++){
a[i]=s[i-1]-'A'+1;
pos[a[i]].push_back(i);
if(pos[a[i]].size()&1)++cnt;
else --cnt;
}
//if(n%2==0&&cnt)return puts("-1"),0;
//if(n%2==1&&cnt>1)return puts("-1"),0;
if(cnt){
int now=0;
for(int i=1;i<=26;i++)if(pos[i].size()&1){
now=pos[i][pos[i].size()/2];
vis[now]=1;
fin[n/2+1]=now;
//cout<<3/2<<endl;
//cout<<now<<" "<<pos[i][0]<<" "<<pos[i][1]<<" "<<pos[i][2]<<" "<<pos[i][3]<<" "<<pos[i].size()<<endl;
break;
}
}
for(int i=1;i<=n/2+len;i++){
if(vis[i]){
++len;continue;
}
int x=a[i];
vis[i]=vis[pos[x].back()]=1;
fin[i-len]=i;fin[n-(i-len)+1]=pos[x].back();
pos[x].pop_back();
}
//for(int i=1;i<=n;i++)cout<<fin[i]<<" ";cout<<endl;
int tot=0;
for(int i=n;i>=1;i--){
tot+=query(fin[i]);
add(fin[i],1);
}
cout<<abs(tot);
return 0;
}

2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)的更多相关文章

  1. poj3067 Japan 树状数组求逆序对

    题目链接:http://poj.org/problem?id=3067 题目就是让我们求连线后交点的个数 很容易想到将左端点从小到大排序,如果左端点相同则右端点从小到大排序 那么答案即为逆序对的个数 ...

  2. Palindrome - URAL - 1297(求回文串)

    题目大意:RT   分析:后缀数组求回文串,不得不说确实比较麻烦,尤其是再用线段数进行查询,需要注意的细节地方比较多,比赛实用性不高......不过练练手还是可以的.   线段数+后缀数组代码如下: ...

  3. 马拉车,O(n)求回文串

    马拉车,O(n)求回文串 对整个马拉车算法步骤做个总结: 第一步:将每个原字母用两个特殊字符包围如: aaa --> #a#a#a# abab -->#a#b#a#b 同时可以由这个翻倍的 ...

  4. HDU 1394 Minimum Inversion Number ( 树状数组求逆序数 )

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number                         ...

  5. POJ2985 The k-th Largest Group[树状数组求第k大值+并查集||treap+并查集]

    The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8807   Accepted ...

  6. Codeforces 486E LIS of Sequence --树状数组求LIS

    题意: 一个序列可能有多个最长子序列,现在问每个元素是以下三个种类的哪一类: 1.不属于任何一个最长子序列 2.属于其中某些但不是全部最长子序列 3.属于全部最长子序列 解法: 我们先求出dp1[i] ...

  7. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  8. hdu 4217 Data Structure? 树状数组求第K小

    Data Structure? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  9. poj 2985 The k-th Largest Group 树状数组求第K大

    The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8353   Accepted ...

随机推荐

  1. JavaScript 事件循环(1) —— 从 setTimeout 说起

    转变认知 setTimeout 可能是很多前端工程师爱用的方法,它可以使得一段代码延迟执行,例如: setTimeout(() => console.log('A'), 1000); // 在1 ...

  2. 一图学Python

    网上有这样一张图片,信息量很大,通常会被配上标题"一张图让你学会Python": 这张图流传甚广,但我没有找到明确的出处,图片上附带了 UliPad 的作者 Limodou 的信息 ...

  3. java常见面试问题总结

    JDK1.7 并发的HashMap为什么会引起死循环? hashmap如何解决hash冲突,为什么hashmap中的链表需要转成红黑树? hashmap什么时候会触发扩容? jdk1.8之前并发操作h ...

  4. DispatcherServlet?

    Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应.

  5. Zookeeper 的典型应用场景 ?

    Zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架,开发人员 可以使用它来进行分布式数据的发布和订阅. 通过对 Zookeeper 中丰富的数据节点进行交叉使用,配合 Watch ...

  6. try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?

    答:会执行,在方法返回调用者前执行.

  7. Kafka 缺点?

    由于是批量发送,数据并非真正的实时: 对于mqtt协议不支持: 不支持物联网传感数据直接接入: 仅支持统一分区内消息有序,无法实现全局消息有序: 监控不完善,需要安装插件: 依赖zookeeper进行 ...

  8. 是否使用过 Redis 集群,集群的原理是什么?

    1).Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为 master,继续提供服务. 2).Redis Cluster 着眼于扩展性,在单个 redis ...

  9. Linux 基础优化

    1.操作的最小化原则 1)安装系统最小化 一般情况下安装OS时,软件安装包组(Package Group)的选择: base--------------------------基本环境 editors ...

  10. Spark学习摘记 —— RDD转化操作API归纳

    本文参考 在阅读了<Spark快速大数据分析>动物书后,大概了解到了spark常用的api,不过书中并没有给予所有api具体的示例,而且现在spark的最新版本已经上升到了2.4.5,动物 ...