【多项式】[LGP4173] 残缺的字符串
【多项式】[LGP4173] 残缺的字符串
题意
给定两个有通配符的字符串,跑字符串匹配。
思路
肯定不能用 kmp
(不要问为什么)。
设 为模式串, 为文本串。
定义一个函数 ,且 当且仅当 ,即 的第 位和 的第 位匹配。
定义关于 的函数 ,且 当且仅当 ,即 和 在 的第 位匹配。
那么应该 ,这样看上去没有优化前途。
既然他的值域都是正数,那么上面条件可以等价于 。
可以定义 ,当字符为通配符时其值为 ,否则为其 ASCII
码的值。
那么 函数
还是不好弄,考虑翻转字符串 为 ,那么 。
代入 函数
可以发现每一个加项都是关于 和 的单项式,而他们下标加起来是一个常数 。
因此,关于 的 函数 就可以化成一个多项式计算。
求和可以拆开,三个式子加起来。三个式子处理方式相同。比如第一个式子 ,其实就是取多项式 的第 项系数,其中 表示 中各项系数都变成 次方后的多项式。
所以暴力做一些多项式乘法就可以得出关于 的 函数 的值。
看上去要做 次多项式乘法,常数爆炸。
专业来说,这道题的思路就是构造 的生成函数 。算出后面多项式的系数就可以得到所有的 。
点击查看代码
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <cstring>
const int N=1e5+1;
int n,m;
char s[N],t[N];
int rplcment[N];
int bty[N<<1],mx; // bty[i]: the max beauty in the front i characters.
int ans[N<<1],mn; // ans[i]:the minimum of replacement when catch the beauty bty[i].
const int mod=998244353,PHI=998244352,G=3,invG=332748118;
inline int fastpow(long long a,int k) {
int res=1;
while(k) {
if(k&1) res=a*res%mod;
a=a*a%mod; k>>=1;
}
return res;
}
inline int plus(int x,int y) { x+=y-mod; return x+((x>>31)&mod); }
inline int minus(int x, int y) { x-=y; return x+((x>>31)&mod); }
typedef std::vector<int> poly;
inline void NTT(poly& a,const int limit,const int B[],const int I=1) {
for(int i=1;i<limit;++i) if(i<B[i]) a[i]^=a[B[i]]^=a[i]^=a[B[i]];
for(int slen=1;slen<limit;slen<<=1) {
const int g = fastpow(I==1? G:invG,PHI/(slen<<1));
for(int j=0;j<limit;j+=slen<<1) {
long long rt=1;
for(int opt=0;opt<slen;++opt) {
const int x=a[j+opt],y=a[j+opt+slen]*rt%mod;
a[j+opt]=plus(x,y); a[j+opt+slen]=minus(x,y);
rt=rt*g%mod;
}
}
}
}
inline poly operator*(poly a,poly b) {
const int deg=a.size()+b.size()-2;
int n,k=0;
while((1<<++k)<=deg);
static int *B=(int*)malloc(sizeof(int));
if((n=1<<k)!=B[0]) {
B=(int*)realloc(B,sizeof(int)*n);
B[0]=0;
for(int i=1;i<n;++i) B[i]=(B[i>>1]>>1)|((i&1)<<(k-1));
B[0]=n;
}
a.resize(n+1); b.resize(n+1);
NTT(a,n,B); NTT(b,n,B);
for(int i=0;i<=n;++i) a[i]=1ll*a[i]*b[i]%mod;
NTT(a,n,B,-1);
a.resize(deg+1);
const long long inv=fastpow(n,mod-2);
for(int i=0;i<=deg;++i) a[i]=inv*a[i]%mod;
return a;
}
inline int hsh(char s) {
if(s=='?') return 0;
return s;
}
inline void work() {
poly a,b,c,d;
a.resize(n); b.resize(m);
for(int i=0;i<n;++i) a[i]=hsh(s[i]);
for(int j=0;j<m;++j) b[j]=hsh(t[j]);
std::reverse(b.begin(),b.end());
c=a; d=b;
for(int i=0;i<n;++i) c[i]=c[i]*c[i]*c[i];
for(int j=0;j<m;++j) d[j]=d[j]*d[j]*d[j];
c=b*c; d=a*d;
for(int i=0;i<n;++i) a[i]=a[i]*a[i];
for(int j=0;j<m;++j) b[j]=b[j]*b[j];
a=a*b;
memset(rplcment,0x80,sizeof(rplcment));
for(int i=0;i<=n-m;++i) if(c[i+m-1]+d[i+m-1]-(a[i+m-1]<<1)==0) rplcment[i+m-1]=0;
int tmp=0; for(int i=0;i<m;++i) tmp+=s[i]=='?';
for(int i=m-1;i<n;++i) {
if(rplcment[i]==0) rplcment[i]=tmp;
tmp+=(s[i+1]=='?')-(s[i-m+1]=='?');
}
return;
}
int main() {
scanf("%d%s%d",&n,s,&m);
for(int i=0;i<m;++i) t[i]=(i&1? 'b':'a');
work();
int i=m-1;
while(i<n+m) {
if(rplcment[i]>=0) bty[i]=mx+1, ans[i]=mn+rplcment[i];
else bty[i]=mx, ans[i]=mn;
if(bty[++i-m]>mx) {
mx=bty[i-m];
mn=ans[i-m];
}else if(bty[i-m]==mx) mn=std::min(mn,ans[i-m]);
}
printf("%d\n",mn);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具