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 ...
随机推荐
- 内置方法 __str__ __repr__
内置方法(双下方法,魔术方法) 在不需要程序员定义,本身就存在的类中的方法就是内置方法 内置方法: __名字__ __init__ 不需要我们主动调用,而是在实例化的时候内部自动调用的,存在一种 ...
- Django基础必会
Django基础必会 Django项目目录 mysite -mysite -__init__.py -urls.py(函数和函数的对应关系) -settings.py(Django项目的配置信息) - ...
- docker学习笔记(4)- 应用数据管理(容器外)
简介 docker storage driver支持了image分层存储和容器可写层的存储管理,使用挂载主机目录的方式可以将数据存储在主机的文件系统上或内存中. 之前学习过镜像的分层存储,以Docke ...
- 『现学现忘』Docker基础 — 32、通过DockerFile的方式挂载数据卷
目录 1.简单了解一下DockerFile 2.通过DockerFile的方式挂载数据卷 (1)创建DockerFile文件 (2)编辑Dockerfile文件 (3)构建Dokcer镜像 (4)启动 ...
- 接口(interface)与抽象类(abstract class)两者的异同
首先说明一下,JDK1.8以后接口可以有默认方法和静态方法以及私有方法. 一.概念: 接口(interface):是抽象类的变体,其中所有的方法都是抽象的且不能有方法体,而且只能定义 static f ...
- hanoi(老汉诺塔问题新思维)
#include <stdio.h> //第一个塔为初始塔,中间的塔为借用塔,最后一个塔为目标塔 int i=1;//记录步数 void move(int n, char from,cha ...
- Python 字典(键值对)
Python 字典(键值对) 创建字典 特性:字典中的键不能变,而且唯一 格式:变量名={"键1":值1,"键2":值2} 函数 作用 dict() 强制转换为 ...
- docker-compose配置django web项目容器和EMQX容器
1.Dockerfile FROM gatewayserver_null:v1.1 ADD ./GatewayServer /code ADD ./entrypoint.sh /code# 给entr ...
- FiddlerEverywhere注册账号进行激活失效问题
有关FiddlerEverywhere通过邮件激活账号时,激活链接提示已失效问题:这个链接有进行一个讨论(https://www.telerik.com/forums/unable-to-activa ...
- 关于table表格中点击一个按钮获取该行的某一列的值并将其传到模态框的问题解决
<tbody> {% for item in all_dataset %} <tr> <td>{{ item.nid }}</td> <td> ...