给一个序列,选择其中一个区间,这个区间内的数字顺序可以随意互换。问有多少这样的选择使得整个序列(不是选择的区间)是一个回文。
说明:为了要使得整个序列是一个回文,可以选择一个区间对里面的数字进行调整,然后使得整个串是一个回文。
问有多少这样的区间可供选择?
Input
输入共2行。
第一行有一个整数n。(1 <= n <= 100,000)
第二行n个整数a[i],(0<=a[i]<=n).
Output
对于每一组数据,输出答案占一行。
还是跑去cf上看题解...
先把两端回文的去掉,对于剩下的,分别求出要使序列合法,需要选择的最短前缀、后缀。然后就可以算了。。。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #define ll long long 7 #define ui unsigned int 8 #define ull unsigned long long 9 const int maxn=100233,inf=1002333333; 10 int a[maxn],b[maxn],rest[maxn],need[maxn]; 11 int i,j,k,n,m; 12 13 int ra,fh;char rx; 14 inline int read(){ 15 rx=getchar(),ra=0,fh=1; 16 while((rx<'0'||rx>'9')&&rx!='-')rx=getchar(); 17 if(rx=='-')fh=-1,rx=getchar(); 18 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra*fh; 19 } 20 21 22 int main(){register int i,j; 23 while(scanf("%d",&n)!=EOF){ 24 for(i=1;i<=n;i++)a[i]=read(); 25 for(m=1;(m<<1)<=n&&a[m]==a[n-m+1];m++); 26 if((m<<1)>n){printf("%lld ",1ll*n*(n+1)>>1);continue;} 27 28 int n1=n-((m-1)<<1); 29 memset(rest,0,(n+1)<<2),memset(need,0,(n+1)<<2); 30 for(i=1;i<=n1;i++)rest[b[i]=a[i+m-1]]++; 31 int odd=0; 32 for(i=0;i<=n;i++)odd+=rest[i]&1; 33 if(odd>(n1&1)){puts("0");continue;} 34 35 for(i=n1;i;i--){ 36 rest[b[i]]--,need[b[i]]++; 37 if((i<<1)<=n1) 38 if(b[i]==b[n1-i+1])need[b[i]]-=2;else break; 39 if((i<<1)==n1+1)need[b[i]]--; 40 if(need[b[i]]>rest[b[i]])break; 41 }int L=i; 42 43 memset(rest,0,(n+1)<<2),memset(need,0,(n+1)<<2); 44 for(i=1;i<=n1;i++)rest[b[i]]++; 45 for(i=1;i<=n1;i++){ 46 rest[b[i]]--,need[b[i]]++; 47 if((i<<1)>n1+1) 48 if(b[i]==b[n1-i+1])need[b[i]]-=2;else break; 49 if((i<<1)==n1+1)need[b[i]]--; 50 if(need[b[i]]>rest[b[i]])break; 51 }int R=n1-i+1; 52 // printf(" m:%d L:%d R:%d ",m,L,R); 53 printf("%lld ",1ll*m*(m + 2*n1-L-R)); 54 } 55 }