您的位置:首页 > 其它

tsinsen A1043. 完美的代价

2016-02-26 19:29 363 查看
A1043. 完美的代价

时间限制:1.0s 内存限制:512.0MB
总提交次数:1985
AC次数:446 平均分:44.86

问题描述

  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。

  交换的定义是:交换两个相邻的字符

  例如mamad

  第一次交换 ad : mamda

  第二次交换 md : madma

  第三次交换 ma : madam (回文!完美!)

输入格式

  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)

  第二行是一个字符串,长度为N.只包含小写字母

输出格式

  如果可能,输出最少的交换次数。

  否则输出Impossible

样例输入

5

mamad

样例输出

3

题解:先从简单的说起,如何判断Impossible,如果长度为偶数,那么所有出现过的字符的个数必须都是偶数,这样才能保证一一对应;如果是奇数,那么允许有一个字符的个数是奇数。如果上述条件不满足,直接输出Impossible就可以了。

如何求最少的交换次数呢?首先先把字符串翻转,然后让原串与翻转串相同的字符一一对应,例如mamad ,翻转后为damam,但是得到的数列不是54321,而应该是52143,也就是说原字符串中某个字符第一次对应翻转字符串的第一次出现,得到数列后求一下该数列的逆序对数除以2即为答案。

为什么呢?因为把原串转成翻转串的过程中必经过是回文串的时刻。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int a[8100],b[8100],n,m,ans,ch[30][8100],p[8100],r[8100];
int id[30];
void pd()
{
if (n%2==0)
{
for (int i=1;i<=26;i++)
if (id[i]%2!=0)
{
printf("Impossible\n");
exit(0);
}
}
else
{
int k=0;
for (int i=1;i<=26;i++)
if (id[i]%2!=0)
k++;
if (k>1)
{
printf("Impossible\n");
exit(0);
}
}
}
void mergesort(int s,int t)
{
if (s==t) return;
int mid=(s+t)/2;
mergesort(s,mid); mergesort(mid+1,t);
int i=s; int j=mid+1; int mp=s;
int k[8100]; memset(k,0,sizeof(k));
while (i<=mid&&j<=t)
{
if (r[i]<r[j])
k[mp]=r[i],i++,mp++;
else
k[mp]=r[j],ans+=mid-i+1,j++,mp++;
}
for (int l=i;l<=mid;l++)
k[mp]=r[l],mp++;
for (int l=j;l<=t;l++)
k[mp]=r[l],mp++;
for (int l=s;l<=t;l++)
r[l]=k[l];
}
int main()
{
memset(id,0,sizeof(id));
scanf("%d\n",&n);
for (int i=1;i<=n;i++)
{
char c; c=getchar();
int cc=c-96;
id[cc]++;  ch[cc][0]++;
ch[cc][ch[cc][0]]=i;
a[i]=cc; b[n-i+1]=cc;
}
pd();
for (int i=1;i<=n;i++)
{
p[b[i]]++;
r[i]=ch[b[i]][p[b[i]]];
}
/*for (int i=1;i<=n;i++)
printf("%d ",r[i]);
cout<<endl;*/
mergesort(1,n);
printf("%d",ans/2);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: