[bzoj3160] 万径人踪灭

2023-11-10 21:40
文章标签 万径 人踪 bzoj3160

本文主要是介绍[bzoj3160] 万径人踪灭,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

img

img

Input

img

Solution

考虑先忽略不可以连成一段的条件。

那么,暴力的做法就是,枚举一个中心点,暴力找出旁边有多少个对称的点,设数量为\(x\),则这个中心点对答案的贡献为\(2^x-1\)

这样是\(O(n^2)\)的,考虑怎么优化。

对于中心点\(mid\),能对\(x\)造成贡献的位置\(i,j\),一定是满足\(i+j=mid*2\)\(s[i]=s[j]\)

写出来就是:
\[ ans=\sum_{i=1}^{mid-1}[s_i=s_{mid*2-i}] \]
然后可以发现这其实是一个卷积的形式,那么弄两个多项式\(A,B\)出来,\(A_i=[s[i]=a]\)\(B_i=[s[i]=b]\)

然后分别自乘,\(mid\)处的答案就是:
\[ 2^{A_{mid}+B_{mid}}-1 \]
然后细节注意下就好了。

然后考虑怎么处理连成一段的,这部分要减去。

这个实质上就是原串回文串的个数,跑一边\(manacher\)就好了。

#include<bits/stdc++.h>
using namespace std;void read(int &x) {x=0;int f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}void print(int x) {if(x<0) putchar('-'),x=-x;if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}const int maxn = 1e6+10;
const int mod = 998244353;
const int MOD = 1e9+7;char c[maxn],s[maxn];
int n,a[maxn],b[maxn],f[maxn];
int N,bit,pos[maxn];int qpow(int A,int x,int p) {int res=1;for(;x;x>>=1,A=1ll*A*A%p) if(x&1) res=1ll*res*A%p;return res;
}void ntt(int *r,int op) {for(int i=0;i<N;i++) if(pos[i]>i) swap(r[i],r[pos[i]]);for(int i=1;i<N;i<<=1) {int wn=qpow(op==1?3:qpow(3,mod-2,mod),(mod-1)/(i<<1),mod);for(int j=0;j<N;j+=(i<<1))for(int k=0,w=1;k<i;k++,w=1ll*w*wn%mod) {int x=r[j+k],y=1ll*w*r[i+j+k]%mod;r[j+k]=(x+y)%mod,r[i+j+k]=(x-y+mod)%mod;}}if(op==-1) {int inv=qpow(N,mod-2,mod);for(int i=0;i<N;i++) r[i]=1ll*r[i]*inv%mod;}
}int manacher() {int res=0,cnt=0;s[cnt]='$',s[++cnt]='%';for(int i=1;i<=n;i++) s[++cnt]=c[i],s[++cnt]='%';int mid=1,mr=1;for(int i=1;i<=cnt;i++) {f[i]=min(mr-i,f[mid*2-i]);while(s[i+f[i]]==s[i-f[i]]) f[i]++;if(i+f[i]>mr) mr=i+f[i],mid=i;res=(res+f[i]/2)%MOD;}return res;
}int main() {scanf("%s",c+1);n=strlen(c+1);for(int i=1;i<=n;i++) if(c[i]=='a') a[i]=1;else b[i]=1;N=1,bit=0;while(N<=(n<<1)) N<<=1,bit++;for(int i=0;i<N;i++) pos[i]=pos[i>>1]>>1|((i&1)<<(bit-1));ntt(a,1),ntt(b,1);for(int i=0;i<N;i++) a[i]=1ll*a[i]*a[i]%mod,b[i]=1ll*b[i]*b[i]%mod;ntt(a,-1),ntt(b,-1);int ans=0;for(int i=2;i<=n*2;i++) {if(!(i&1)) {if(c[i>>1]=='a') a[i]++;else b[i]++;}a[i]>>=1,b[i]>>=1;ans=(ans+qpow(2,a[i]+b[i],MOD)-1)%MOD;}ans=(ans-manacher()+MOD)%MOD;write((ans+MOD)%MOD);return 0;
}

转载于:https://www.cnblogs.com/hbyer/p/10329360.html

这篇关于[bzoj3160] 万径人踪灭的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/385424

相关文章

bzoj 3160 万径人踪灭 FFT

万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1936  Solved: 1076[Submit][Status][Discuss] Description Input Output Sample Input Sample Output HINT   题目大意:给定一个由'a'和'b'构成的字符串,求不

BZOJ 3160 万径人踪灭 解题报告

这个题感觉很神呀。将 FFT 和 Manacher 有机结合在了一起。 首先我们不管那个 “不能连续” 的条件,那么我们就可以求出有多少对字母关于某一条直线对称,然后记 $T_i$ 为关于直线 $i$ 对称的字母对的数量,那么答案(暂记为 $Ans$)就会是: $$Ans = \sum 2^{T_i}-1$$ 在不管那个 “不能连续” 的条件的时候,这个应该是显然的。 怎么算的话,我们弄两次。分

BZOJ 3160 万径人踪灭

Description Input Output Sample Input Sample Output HINT 先在串中两两之间插入#,形成新串s,主要是考虑中心不在列上令$f[i]$表示以i为中心,两边为a或b且相同的对数$f[i]=\sum_{x+y=i*2}[s[x]==s[y]]$注意$s[x]s[y]$不能为#发现这其实是一个卷积,于是FFT,求出f[i]于是通

BZOJ3160:万径人踪灭(FFT,Manacher)

Solution $ans=$回文子序列$-$回文子串的数目。 后者可以用$manacher$直接求。 前者设$f[i]$表示以$i$为中心的对称的字母对数。 那么回文子序列的数量也就是$\sum_{i=0}^{n-1}2^{f[i]-1}$ 构造两个数组$a[i],b[i]$。若第$i$位为$a$,那么$a[i]=1$,否则$b[i]=1$。 可以发现$a$数组自身卷积就是$a$字

【bzoj3160】万径人踪灭 FFT

【bzoj3160】万径人踪灭 FFT 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3160 我是一个傻叉 微笑脸 1 #include<bits/stdc++.h> 2 #define inf 1000000000 3 #define ll long long 4 #define N 200005 5 #de

BZOJ3160【万径人踪灭】 【FFT】

。。恩 打了四五遍 不会也背出来了。。 BZOJ3160 【听说时限紧?转C++的优势么?】 上AC代码 fft 1 /*Problem: 3160 2 User: cyz666 3 Language: C++ 4 Result: Accepted 5 Time:1992 ms 6 Memory:18492 kb 7 ********

NKOJ 2895 万径人踪灭(Manacher+FFT)

P2895 万径人踪灭 题目描述 如果机房马上要关门了,或者你急着要和MM 约会,请直接跳到第六个自然段。 VFleaKing注意到了这条上山下山的土路,有些地方能欣赏到美景,有些地方则不能。把上山的道路每10cm分为一小段,则对于每一小段,用a 表示能欣赏到美景,用b表示不能欣赏到美景,就能得到一个只含a,b的字符串s。当然由于下山和上山是一条路,所以下山的道路的字符串就是将上山的道路的