【Tisinsen1043】完美的代价(字符串+树状数组)
2016-02-20 17:25
253 查看
题目描述
传送门题解
判断Impossible的条件很简单,就是看字符串中的一样的字符是否出现的是偶数次(长度为奇数的话只允许出现一个字符出现奇数词)。计算ans:
首先将原串中的字母编号,编号为其在原串中的位置;
然后把整个字符串反置,然后我们就得到了一个新的编号序列;
你不要以为反置了之后新的编号序列一定也是原先编号序列的反置,我们规定反置之后字母的相对位置不变。什么意思呢,就是说字符串反置了之后第一个出现的字母的编号为原串第一个出现的字母的编号,如mamad,编号为12345,反置之后damam,编号为52143,而不应为54321;
看到这你也许就明白怎么做了,直接求新的编号序列的逆序对数再/2即可得到ans;
证明是这样的:首先相同的字母不用交换,因为它们交换是等价的;其次从原串换到新串的过程中一定可以找到一种方案使中间过程出现一次回文串。
归并排序求逆序对或者树状数组维护即可。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int max_s=8e3+5; const int max_c=max_s*2; char s[max_s]; int cnt[30],loca[30][max_s],point[30],a[max_s]; int C[max_c]; int len,ans; inline void add(int loc,int val){ for (int i=loc;i<=len;i+=i&(-i)) C[i]+=val; } inline int query(int loc){ int ans=0; for (int i=loc;i>0;i-=i&(-i)) ans+=C[i]; return ans; } int main(){ scanf("%d",&len); scanf("%s",s); //Judge for (int i=0;i<len;++i) cnt[s[i]-'a']++; bool pd=false; for (int i=0;i<26;++i) if (cnt[i]%2!=0){ if (pd){ printf("Impossible\n"); return 0; } else pd=true; } //location for (int i=0;i<len;++i){ int now=s[i]-'a'; loca[now][++point[now]]=i+1; } memset(point,0,sizeof(point)); //turn for (int i=len-1;i>=0;--i){ int now=s[i]-'a'; a[len-i]=loca[now][++point[now]]; } //BIT for (int i=len;i>=1;--i){ add(a[i],1); ans+=query(a[i]-1); } ans/=2; printf("%d\n",ans); }
相关文章推荐
- Spring 多数据源事务配置问题
- hdoj2029 Palindromes _easy version
- golang(5):编写WebSocket服务,client和html5调用
- AC自动机最好讲解
- Apache2.4.9 多域名多网站配置
- android发送邮件(包括附件)
- Java集合类的区别
- 如何使用cocoa pods管理第三方框架
- php上传文件处理
- 安卓开发工具Eclipse、SDK等升级攻略
- uva 11021 推概率公式
- Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)
- 《程序是怎么跑起来的》读书笔记二-对程序员来说CPU是什么
- Java enum(枚举)的用法详解(转)
- arm-linux-gcc: Command not found 问题解决
- 计算机网络--http代理server的设计与实现
- svn创建分支和合并
- uva 10561 SG
- 《长尾理论》读书笔记(上-2-1)
- MySQL 变量和条件