/*
分析:
(找规律+递推) && (线段树 || 树状数组),非区间dp方法。
以后都不准备再贴水题了,不过这题我比赛时想到的方法和解题报告的方法不一样,所
以贴下。。
1. 经过观察,发现性质:对于str[i]==str[j] && i<j,那么所有首位为a、末位为b、且满足
(i<a && a<=b && b<j)的回文序列,一定可以在两端加上str[i]和str[j]后,构成一个新的回
文序列,并且这个回文序列的首元素为str[i]、尾元素为str[j];
2. 维护两个数组,ans[N]和cnt[N],ans[i]表示以元素i为首位的回文序列的数量、cnt[i]表
示以元素i结尾的回文序列的数量;
3. 逆向遍历str(正向也行),初始化ans[i]=1,cnt[i]=1,代表自己单独为一个序列;同
时用指针j,从str尾向前遍历while(i<j),当str[i]==str[j]的时候,进行如下操作:
(1)ans[i]++,cnt[j]++,(代表i和j单独构成一个序列);
(2)统计sum=所有cnt[k]的和,k满足(i<k && k<j),然后ans[i]+=sum,cnt[i]+=sum;
最后统计所有的ans的SUM,既为所求。
对于3.(2),需要用树状数组或者线段树快速求和。
源自-------------------------------------Ice_Crazy
2013-08-02
*/
#include"iostream" #include"cstdio" #include"cstring" using namespace std; const int N=1006; const int mod=10007; int n,lowbit[N]; __int64 C[N],ans[N]; char str[N]; void update(int k,int dir) { while(0<k && k<=n) { C[k]=(C[k]+dir)%mod; k+=lowbit[k]; } } int sum(int k) { __int64 p=0; while(0<k && k<=n) { p=(p+C[k])%mod; k-=lowbit[k]; } return p; } int main() { int T,Case; int i,l; __int64 a,b,t; __int64 hehe; for(i=1;i<=1000;i++) lowbit[i]=i&(-i); cin>>T; for(Case=1;Case<=T;Case++) { hehe=0; scanf("%s",str+1); memset(C,0,sizeof(C)); memset(ans,0,sizeof(ans)); for(n=1;str[n];n++); n--; for(i=n;i>=1;i--) { ans[i]=1; update(i,1); for(l=n;l>i;l--) { if(str[l]==str[i]) { a=sum(i); b=sum(l-1); t=(b-a)%mod; while(t<0) t+=mod; ans[i]=(ans[i]+1+t)%mod; update(l,1+t); } } } hehe=0; for(i=1;i<=n;i++) hehe=(hehe+ans[i])%mod; printf("Case %d: %I64d\n",Case,hehe); } return 0; }