Codeforces Round #285 (Div. 2) E. Misha and Palindrome Degree 二分+容斥

E. Misha and Palindrome Degree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Misha has an array of n integers indexed by integers from 1 to n. Let's define palindrome degree of array a as the number of such index pairs (l, r)(1 ≤ l ≤ r ≤ n), that the elements from the l-th to the r-th one inclusive can be rearranged in such a way that the whole array will be a palindrome. In other words, pair (l, r) should meet the condition that after some rearranging of numbers on positions from l to r, inclusive (it is allowed not to rearrange the numbers at all), for any 1 ≤ i ≤ n following condition holds: a[i] = a[n - i + 1].

Your task is to find the palindrome degree of Misha's array.

Input

The first line contains integer n (1 ≤ n ≤ 105).

The second line contains n positive integers a[i] (1 ≤ a[i] ≤ n), separated by spaces — the elements of Misha's array.

Output

In a single line print the answer to the problem.

Sample test(s)
input
3
2 2 2
output
6
input
6
3 6 5 3 3 5
output
0
input
5
5 5 2 5 2
output
4

题意:给出n个数,若有一个区间,只重排那个区间的数字(可不排),使得数组是构成一个回文,则它就是答案之一


题解:

①若本身就是回文,则答案就是1+2+……+n-1+n,即(1+n)*n/2

②判断数字个数,若n为奇数个,则只能有一个数字个数是奇数个,偶数则不能有数字个数是奇数个的。否则肯定构不成回文,答案为0

③从两头往中间判断,相同的把数字个数-2,这些数字不是必须要重排的(可排可不排),当找到两个数字不同的时候,就需要两头各找出一个最小区间,使得他们重排后为回文。

要找最小区间,容易想到二分找,但怎么判断该区间满足条件就比较麻烦。首先得确定二分的下界,若中间有部分数字相同的话,则区间有可能只存在一边或两边各占,下界就是中间开始不同的地方,上界就是③中对应另一个不同的数字位置,若中间数字完全没有相同的话,则一定是两边各占,这样下界就是(n+1)/2,上界也是③中对应另一个不同的数字位置。

至于判断区间是否满足,假设当前区间长度为len1,另一半区间为len2,则只要比较两个区间大小,然后找到小的那个,然后判断该区间是否有数字大于该数字总的一半即为不满足,否则满足。

获得两个最小区间后,用容斥定律来解,假设两个区间为[l1,r1],[l2,r2]。左区间的总方案=l1*(n-r1+1),右区间总方案=(n-r2+1)*l1。减去的共同的方案数=l1*(n-r2+1)


#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
using namespace std;
#define LL long long
const int maxn=100005;
map<int,int> mp,mp1,mp2;
map<int,int> ::iterator it;
struct sw{
	int l,r;
	sw(){}
	sw(int ll,int rr){
		l=ll,r=rr;
	}
}ans[2];
int n;
int num[maxn];
int flag,cou=0,cou2=0,now,key;
unsigned LL res=0;
bool check(int l,int r){
	mp1.clear();
	int len1=r-l+1,len2=n-2*now-len1;
	if(len2<len1){
		if(l==now+1){
			r=n-l+1;
			l=r-len2+1;
		}
		else {
			l=n-r+1;
			r=l+len2-1;
		}
	}
	for(;l<=r;l++)
		mp1[num[l]]++;
	for(it=mp1.begin();it!=mp1.end();it++){
		if(it->second>mp[it->first]/2)
			return 0;
	}
	
	return 1;	
}
int main(void){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&num[i]);
		mp[num[i]]++;
	}
	flag=n%2;
	for(it=mp.begin();it!=mp.end();it++){
		if(it->second%2) cou++,key=it->first;
		if(cou>flag) break;
	}
	if(cou>flag) {
		printf("0\n");
		return 0;
	}
	for(int s=1,e=n;s<e;s++,e--){
		if(num[s]!=num[e]){
			now=s-1;
			int l=1,r=e-s;
			for(int i=(n+1)/2,j=(n+2)/2;1;i--,j++)
				if(num[i]!=num[j]||(flag&&i==(n+1)/2&&num[i]!=key)){
					key=i-s;
					l=key;
					break;
				}
			while(l<=r){
				int mid=(l+r)>>1;
				if(check(s,s+mid))
					r=mid-1;
				else l=mid+1;
			}
			ans[cou2++]=sw(s,s+l);
			l=key,r=e-s;
			while(l<=r){
				int mid=(l+r)>>1;
				if(check(e-mid,e))
					r=mid-1;
				else l=mid+1;
			}
			ans[cou2++]=sw(e-l,e);
			break;
		}
		else mp[num[s]]-=2;
	}
	if(cou2==0){
		res=1LL*(n+1)*n/2;
		cout<<res<<endl;
		return 0;
	}
	{
		int l1,l2,r1,r2;
		l1=ans[0].l,l2=ans[1].l;
		r1=ans[0].r,r2=ans[1].r;
		res+=l1*(n-r1+1)+(n-r2+1)*l2;
		res-=l1*(n-r2+1);
		cout<<res<<endl;
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值