题目 1467: [蓝桥杯][基础练习VIP]完美的代价

题目链接:https://www.dotcpp.com/oj/problem1467.html?sid=2421345&lang=1#editor

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

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

例如mamad

第一次交换  ad  :  mamda

第二次交换  md  :  madma

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

输入

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

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

输出

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

否则输出Impossible 

样例输入

5 
mamad 

样例输出

3

当时没来的及做,后来看的时候考虑简单了wa了。

思路(对称位置的位置差):

首先说一下不成立的情况:

当n为偶数的时候,若存在奇数个的字母,就会不成立。

当n为奇数的时候,若奇数个的字母超过一个,就会不成立。

接下来讲一下成立的情况下最少的移动次数。

设置两个变量,i和j,分别指向字符串a的首尾。

如果a[i]==a[j],i++,j--;不做交换

如果a[i]!=a[j],从k=j-1,来寻找使得a[i]=a[k],这里又分两种情况。

1.i!=k时,说明找到了,并对字符串的字符进行交换。

2.i==k,说明这是奇字符串中的奇字符。先不做任何处理,只是加上步数(与中间位置的差值)。

这里说明一下为什么不进行交换(不做处理):

例如字符串 cdaabbc 。若对字符d交换后是 caadbbc 那么在之后的交换中会多和d交换一次。

不做处理,把之后的交换完成,最后字符d交换当前位置与中间位置的差值的次数就可。

AC代码:

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#define cla(a, sum) memset(a, sum, sizeof(a))
#define rap(i, m, n) for(i=m; i<=n; i++)
#define rep(i, m, n) for(i=m; i>=n; i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;
const int Inf = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 1e4+5;

int n;
char a[maxn];
int c[30]={0};

int main()
{
    cin>>n;
    scanf("%s",a+1);
    int i,j,k;
    for(i=1;i<=n;i++){
    	j=a[i]-'a'+1;
    	c[j]++;
	}
	k=0;
	rap(i,1,26){
		if(c[i]%2)k++;
	}
	if(k>=2||(n%2==0&&k==1)){//不成立 
		printf("Impossible");
		return 0;
	}
	int sum=0;
    for(i=1,j=n;i<j;i++){
    	if(a[i]==a[j]){
    		j--;
    		continue;
		}
		int ans=0;
		for(k=j-1;k>i;k--){
			ans++;
			if(a[k]==a[i]){
			    break;	
			}
		}
		if(k==i){//特殊情况,奇字符 
			sum+=n/2-i+1;
			continue;
		} 
		sum+=ans;
		for(;k<j;k++){
			swap(a[k],a[k+1]);
		}
		j--;
	}
	cout<<sum<<endl; 
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值