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
#include
#include
#include
using namespace std;
#define LL long long
const int maxn=100005;
map mp,mp1,mp2;
map ::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(len2second>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>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<



你可能感兴趣的:(二分)