2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)
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]求回文串(树状数组求逆序对)的更多相关文章
- poj3067 Japan 树状数组求逆序对
题目链接:http://poj.org/problem?id=3067 题目就是让我们求连线后交点的个数 很容易想到将左端点从小到大排序,如果左端点相同则右端点从小到大排序 那么答案即为逆序对的个数 ...
- Palindrome - URAL - 1297(求回文串)
题目大意:RT 分析:后缀数组求回文串,不得不说确实比较麻烦,尤其是再用线段数进行查询,需要注意的细节地方比较多,比赛实用性不高......不过练练手还是可以的. 线段数+后缀数组代码如下: ...
- 马拉车,O(n)求回文串
马拉车,O(n)求回文串 对整个马拉车算法步骤做个总结: 第一步:将每个原字母用两个特殊字符包围如: aaa --> #a#a#a# abab -->#a#b#a#b 同时可以由这个翻倍的 ...
- HDU 1394 Minimum Inversion Number ( 树状数组求逆序数 )
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number ...
- POJ2985 The k-th Largest Group[树状数组求第k大值+并查集||treap+并查集]
The k-th Largest Group Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 8807 Accepted ...
- Codeforces 486E LIS of Sequence --树状数组求LIS
题意: 一个序列可能有多个最长子序列,现在问每个元素是以下三个种类的哪一类: 1.不属于任何一个最长子序列 2.属于其中某些但不是全部最长子序列 3.属于全部最长子序列 解法: 我们先求出dp1[i] ...
- POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)
树状数组求逆序对 转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...
- hdu 4217 Data Structure? 树状数组求第K小
Data Structure? Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- poj 2985 The k-th Largest Group 树状数组求第K大
The k-th Largest Group Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 8353 Accepted ...
随机推荐
- 定位一个oom问题
当系统出现oom问题时,我们一般的定位思路是怎样的? 系统OOM常见的原因有: 1.用户态内存需求过多,资源不足: 2.大页配置不正确: 3.水位线值异常: 4.slab内存过多: 5.rcu异常: ...
- springcloud学习03-spring cloud eureka(下)
7.配置服务提供者(生产者) 7.1.配置resources/application.yml. 值eureka.client.service-url(或serviceUrl).defaultZone是 ...
- IIS将应用程序池配置为在计划时间执行回收 (IIS 7)
将应用程序池配置为在计划时间执行回收 您可以通过以下方法执行此过程:使用用户界面 (UI).在命令行窗口中运行 Appcmd.exe 命令.直接编辑配置文件或编写 WMI 脚本. 如下只介绍用户界面U ...
- Mysql之锁(一)
读锁与写锁 读锁:共享锁.Shared Locks.S锁. 写锁:排他锁.Exclusive Locks.X锁. 读锁:只能读不允许写 写锁:不能读也不能写,只允许自己写 但是允许其他事务进行普通的s ...
- Spring 和 SpringBoot 有什么不同?
Spring 框架提供多种特性使得 web 应用开发变得更简便,包括依赖注入.数据绑定.切面编程.数据存取等等. 随着时间推移,Spring 生态变得越来越复杂了,并且应用程序所必须的配置文件也令人觉 ...
- Math.round(11.5) 等于多少?Math.round(-11.5)等于 多少?
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11.四舍五 入的原理是在参数上加 0.5 然后进行下取整.
- springboot远程debug调试
案例代码: https://www.cnblogs.com/youxiu326/p/sb_promotion.html 1.首先去编辑器打开项目 2.打开Edit Configurations ...
- read,readline,readlines的特点与区别
1.read 读取全部文件 with open("test.text", "r",encoding='utf8') as f: print(f.read()) ...
- 《手把手教你》系列基础篇(八十四)-java+ selenium自动化测试-框架设计基础-TestNG日志-上篇(详解教程)
1.简介 TestNG还为我们提供了测试的记录功能-日志.例如,在运行测试用例期间,用户希望在控制台中记录一些信息.信息可以是任何细节取决于目的.牢记我们正在使用Selenium进行测试,我们需要有助 ...
- 判断集合中存在String字符串 或 判断集合中不存在String字符串
一.使用场景 用于集合中有多个相近的字符,无法使用包含判断 如: 这里如果我想判断以上集合中是否包含"信封件-DE"就会被"信封件-DE2"影响到 毕竟:&qu ...