Misha and Palindrome Degree

Misha and Palindrome Degree

题目链接:http://codeforces.com/problemset/problem/501/E

贪心

如果区间[L,R]满足条件,那么区间[L',R'](L'<=L,R<=R')必然满足条件,所以只需要找到满足条件的最小区间即可。首先去除两边相同的区间,剩下的区间为[l,r],因为区间[l,r]的两端不相同,所以要找的最小区间必然包含区间[l,r]的最左端或者最右端。观察到所选区间内的同种元素个数必需大于等于整个区间内同种元素的个数,以此来找到最小区间。

计算区间个数的示意图:

代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #define N 100000
 4 #define LL long long
 5 using namespace std;
 6 LL a[N+5];
 7 LL cnt[N+5];
 8 LL jud[N+5];
 9 LL n,l,r,single,sum;
10 int main(void){
11     scanf("%I64d",&n);
12     for(LL i=0;i<n;++i){
13         scanf("%I64d",a+i);
14         cnt[a[i]]++;
15     }
16     for(LL i=0;i<=n;++i)
17         if(cnt[i]&1)single++;
18     if(single>1){
19         printf("0
");
20         return 0;
21     }
22     for(l=0;l<=(n>>1);++l){
23         if(a[l]==a[n-1-l])cnt[a[l]]-=2;
24         else break;
25     }
26     r=n-1-l;
27     if(l>=r){
28         printf("%I64d
",n*(n+1)/2);
29         return 0;
30     }
31     LL left=r;
32     for(;left>=l;--left){//缩小(l,left)的区间
33         jud[a[left]]++;//统计(left,r)中的元素个数
34         if(jud[a[left]]*2>cnt[a[left]]){
35             if(left>((n-1)>>1))break;//区间无法继续缩小
36             if(a[left]!=a[n-1-left])break;//如果相等,区间可以更小
37             if(cnt[a[left]]%2==0&&left==n-1-left)break;//如果是中间奇数的,继续缩小
38         }
39     }
40     sum+=(r-left)*(l+1);
41     memset(jud,0,sizeof(jud));
42     int right=l;
43     for(;right<=r;++right){
44         jud[a[right]]++;
45         if(jud[a[right]]*2>cnt[a[right]]){
46             if(right<((n-1)>>1))break;
47             if(a[right]!=a[n-1-right])break;
48             if(cnt[a[right]]%2==0&&right==n-1-right)break;
49         }
50     }
51     sum+=(right-l)*(n-r);
52     sum+=(n-r)*(l+1);
53     printf("%I64d
",sum);
54 }
原文地址:https://www.cnblogs.com/barrier/p/5781150.html