1 条题解
-
0
自动搬运
来自洛谷,原作者为

Orion545
**搬运于
2025-08-24 21:57:36,当前版本为作者最后更新于2018-04-14 15:04:27,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
广告
蒟蒻のblog
正文
首先我们明确一个想法:答案等于“位置对称的回文子序列数”-“回文子串数”,而后面的回文子串数可以通过做出来
所以我们的问题转化为:求“位置对称的会文字序列个数”
我们考虑以字符串的第个字符作为一个子序列的对称中心
那么当时,我们的答案就加一种选择
如果对于,有个这样的相等字符对,那么最终以第个位置为中心的答案就是
为什么呢?
因为算上对称中心本身,一共有组可以选或者不选的字符,除去全都不选的一种就是答案
然而这是i为某个特定字符的情况,或者说i为整数的情况,但是i还有在两个字符中间的情况,此时答案就是,因为没有中间的自己那个字符
接下来,我们考虑如何计算每个位置上这样的字符组数量
我们构建两个多项式与,令的所有原串中为'a'的位置系数为1,'b'系数为零,则反过来
然后用自乘,得到的新多项式的第i位的值,就是对称中心为第的,两个字符都是'a'的字符组数,同理
最后我们把和的每一位系数加起来,减去((i&1)^1)(代表对称中心是否在某个字符上),求2的次幂再减去1,最后减去manacher求出的回文子串数目就可以了
Code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; const ll MOD=1e9+7; struct complex{ double x,y; complex(double xx=0,double yy=0){x=xx;y=yy;} complex operator +(const complex &b){return complex(x+b.x,y+b.y);} complex operator -(const complex &b){return complex(x-b.x,y-b.y);} complex operator *(const complex &b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);} }A[400010],B[400010]; const double pi=acos(-1.0); ll n,m,limit=1,cnt=0,r[400010]; void fft(complex *a,double type){ ll i,j,k,mid;complex x,y,w,wn; for(i=0;i<limit;i++) if(i<r[i]) swap(a[i],a[r[i]]); for(mid=1;mid<limit;mid<<=1){ wn=complex(cos(pi/mid),type*sin(pi/mid)); for(j=0;j<limit;j+=(mid<<1)){ w=complex(1,0); for(k=0;k<mid;k++,w=w*wn){ x=a[j+k];y=w*a[j+k+mid]; a[j+k]=x+y;a[j+k+mid]=x-y; } } } } ll s[100010],ans[200010],x[200010],p[200010],sum;char ss[100010]; void manacher(){ ll maxn=-1,id,mx=0,i; for(i=1;i<=(n<<1)+1;i++){ if(i<mx) p[i]=min(p[2*id-i],mx-i); else p[i]=1; while(x[i-p[i]]==x[i+p[i]]) p[i]++; if(mx<i+p[i]){ mx=p[i]+i;id=i; } } } ll qpow(ll x,ll y){ ll re=1; while(y){ if(y&1) re=re*x%MOD; x=x*x%MOD;y>>=1; } return re; } int main(){ ll i; scanf("%s",ss);n=strlen(ss); for(i=0;i<n;i++) s[i+1]=(ss[i]=='a'); for(i=1;i<=(n<<1)+1;i++){ if(i%2) x[i]=2; else x[i]=s[i>>1]; }x[0]=-1,x[(n+1)<<1]=-2; while(limit<=(n<<1)) limit<<=1,cnt++; for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1))); for(i=1;i<=n;i++) A[i].x=B[i].x=s[i]; fft(A,1);fft(B,1); for(i=0;i<=limit;i++) A[i]=A[i]*B[i]; fft(A,-1); for(i=1;i<=(n<<1)+1;i++) ans[i]+=((ll)(A[i].x/limit+0.5)-((i&1)^1)); memset(A,0,sizeof(A));memset(B,0,sizeof(B)); for(i=1;i<=n;i++) A[i].x=B[i].x=(s[i]^1); fft(A,1);fft(B,1); for(i=0;i<=limit;i++) A[i]=A[i]*B[i]; fft(A,-1); for(i=1;i<=(n<<1)+1;i++) ans[i]+=((ll)(A[i].x/limit+0.5)-((i&1)^1)); for(i=1;i<=(n<<1)+1;i++) ans[i]=((ans[i]+((i&1)^1))>>1)+((i&1)^1); for(i=1;i<=(n<<1)+1;i++) ans[i]=qpow(2,ans[i])-1,ans[i]%=MOD; manacher(); for(i=1;i<=(n<<1)+1;i++) ans[i]-=(p[i]>>1),ans[i]%=MOD; for(i=1;i<=(n<<1)+1;i++) sum+=ans[i],sum%=MOD; printf("%lld",sum); }
- 1
信息
- ID
- 3153
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者