解析

通配符匹配的经典题。
设单词串为 AAA,文章串为 BBB。
把 AAA 翻转一下,判断问题就能转化为一个卷积的形式:
F(p)=&i=0m−1match(Ai+1,Bp−i)F(p)=\&_{i=0}^{m-1}match(A_{i+1},B_{p-i})F(p)=&i=0m−1​match(Ai+1​,Bp−i​)
match(a,b)match(a,b)match(a,b) 表示 a,ba,ba,b 两个字符是否互相匹配。
但是这么丑的东西显然难以优化,我们需要更优美的表达形式。
考虑且运算的性质,我们需要一个非法就能检测出非法,那么我们考虑利用平方的非负性,设计一个函数 C(a,b)=(a−b)2C(a,b)=(a-b)^2C(a,b)=(a−b)2,把函数改写成:
F(p)=∑i=0m−1C(Ai+1,Bp−i)F(p)=\sum_{i=0}^{m-1}C(A_{i+1},B_{p-i})F(p)=i=0∑m−1​C(Ai+1​,Bp−i​)
位置合法当且仅当对应函数值为0,把平方拆开分别算再加起来即可。

现在考虑如何加入通配符。
只要 a,ba,ba,b 中有任意一个是通配符,就应该是合法的。
利用 000 乘任何数都是 000 的性质,对于 CCC 函数进行微调:
C(a,b)=(a−b)2jd(a)jd(b)C(a,b)=(a-b)^2jd(a)jd(b)C(a,b)=(a−b)2jd(a)jd(b)
其中 jd(a)jd(a)jd(a) 表示字符 aaa 是否不是 *
这样就可以卷起来算了。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=2e6+100;
const int mod=998244353;
int n,m,k;
inline ll ksm(ll x,ll k){ll res=1;while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}
int r[N];
void init(int n,int &lim){lim=1;int L=0;while(lim<n) lim<<=1,L++;for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
}
void NTT(ll *x,int lim,int op){for(int i=0;i<lim;i++) if(i<r[i]) swap(x[i],x[r[i]]);for(int l=1;l<lim;l<<=1){ll w=ksm(3,(mod-1)/(l<<1));if(op==-1) w=ksm(w,mod-2);for(int st=0;st<lim;st+=(l<<1)){for(ll i=0,now=1;i<l;i++,now=now*w%mod){ll u=x[st+i],v=now*x[st+i+l]%mod;x[st+i]=u+v>=mod?u+v-mod:u+v;x[st+i+l]=u-v<0?u-v+mod:u-v;}}}if(op==-1){ll ni=ksm(lim,mod-2);for(int i=0;i<lim;i++) x[i]=x[i]*ni%mod;}return;
}
void copy(ll *a,ll *b,int n,int lim){assert(n<=lim);memcpy(a,b,sizeof(ll)*n);fill(a+n,a+lim,0);return;
}
void mul(ll *a,ll *b,ll *c,int n,int m){static ll u[N],v[N];static int lim;//for(int i=0;i<n;i++) printf("%lld ",a[i]);putchar('\n');//for(int i=0;i<m;i++) printf("%lld ",b[i]);putchar('\n');init(n+m-1,lim);copy(u,a,n,lim);copy(v,b,m,lim);NTT(u,lim,1);NTT(v,lim,1);for(int i=0;i<lim;i++) c[i]=u[i]*v[i]%mod;NTT(c,lim,-1);//for(int i=0;i<n+m-1;i++) printf("%lld ",c[i]);putchar('\n');//putchar('\n');return;
}
void inv(ll *h,ll *f,int n){static ll t1[N],t2[N];static int lim;if(n==1){f[0]=ksm(h[0],mod-2);return;}inv(h,f,(n+1)>>1);init(n<<1,lim);fill(f+((n+1)>>1),f+lim,0);copy(t1,f,n,lim);copy(t2,h,n,lim);NTT(t1,lim,1);NTT(t2,lim,1);for(int i=0;i<lim;i++) t1[i]=(2*t1[i]-t1[i]*t1[i]%mod*t2[i]%mod+mod)%mod;NTT(t1,lim,-1);memcpy(f,t1,sizeof(ll)*n);return;
}
//499122177
void Sqrt(ll *h,ll *f,int n){static ll t1[N],t2[N];static int lim;if(n==1){f[0]=1;return;}Sqrt(h,f,(n+1)>>1);init(n<<1,lim);fill(f+((n+1)>>1),f+lim,0);inv(f,t1,n);fill(t1+n,t1+lim,0);mul(h,t1,t1,n,n);copy(t2,f,n,lim);NTT(t1,lim,1);NTT(t2,lim,1);for(int i=0;i<lim;i++) t1[i]=(t1[i]+t2[i]%mod)*499122177%mod;NTT(t1,lim,-1);memcpy(f,t1,sizeof(ll)*n);return;
}
void dao(ll *h,ll *f,int n){static ll t[N];static int lim;init(n<<1,lim);copy(t,h,n,lim);f[n-1]=0;for(int i=0;i<n-1;i++) f[i]=t[i+1]*(i+1)%mod;fill(f+n,f+lim,0);return;
}
void jifen(ll *h,ll *f,int n){static ll t[N];static int lim;init(n<<1,lim);copy(t,h,n,lim);f[0]=0;for(int i=1;i<n;i++) f[i]=h[i-1]*ksm(i,mod-2)%mod;fill(f+n,f+lim,0);
}
void Ln(ll *h,ll *f,int n){static ll t1[N],t2[N];static int lim;init(n<<1,lim);inv(h,t1,n);fill(t1+n,t1+lim,0);dao(h,t2,n);mul(t1,t2,t1,n,n);jifen(t1,f,n);return;
}
void Exp(ll *h,ll *f,int n){static ll t1[N],t2[N],t3[N];static int lim;if(n==1){f[0]=1;return;}Exp(h,f,(n+1)>>1);init(n<<1,lim);fill(f+((n+1)>>1),f+lim,0);copy(t1,f,n,lim);copy(t2,h,n,lim);Ln(f,t3,n);fill(t3+n,t3+lim,0);NTT(t1,lim,1);NTT(t2,lim,1);NTT(t3,lim,1);for(int i=0;i<lim;i++) t1[i]=t1[i]*(1+t2[i]-t3[i]+mod)%mod;NTT(t1,lim,-1);memcpy(f,t1,sizeof(ll)*n);return;
}
ll a[N],b[N],c[N],res[N];
bool x[N],y[N];
char s1[N],s2[N];
int ans[N],tot;
signed main() {#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);
#endif
//printf("%d\n",sizeof(a1)/1024/1024);m=read();n=read();scanf(" %s %s",s1+1,s2+1);for(int l=1,r=m;l<r;l++,r--) swap(s1[l],s1[r]);for(int i=1;i<=m;i++) x[i]=(s1[i]!='*'),s1[i]-='a'-1;for(int i=1;i<=n;i++) y[i]=(s2[i]!='*'),s2[i]-='a'-1;for(int i=1;i<=m;i++) a[i]=s1[i]*s1[i]*x[i];for(int i=1;i<=n;i++) b[i]=y[i];mul(a,b,c,m+1,n+1);for(int i=1;i<=n+1;i++) res[i]+=c[i];for(int i=1;i<=m;i++) a[i]=x[i];for(int i=1;i<=n;i++) b[i]=s2[i]*s2[i]*y[i];mul(a,b,c,m+1,n+1);for(int i=1;i<=n+1;i++) res[i]+=c[i];for(int i=1;i<=m;i++) a[i]=s1[i]*x[i];for(int i=1;i<=n;i++) b[i]=s2[i]*y[i];mul(a,b,c,m+1,n+1);for(int i=1;i<=n+1;i++) res[i]-=2*c[i];for(int p=m;p<=n;p++) if(res[p+1]==0) ans[++tot]=p-m+1;printf("%d\n",tot);for(int i=1;i<=tot;i++) printf("%d ",ans[i]);return 0;
}
/*
4
0 1 1
*/

洛谷P4173:残缺的字符串(FFT、通配符匹配)相关推荐

  1. 洛谷 - P4173 残缺的字符串(多项式匹配字符串-NTT)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss 和一个长度为 mmm 的字符串 ttt,都含有通配符 '*',现在问字符串 ttt 可以匹配字符串 nnn 的哪些位置 题目分析 ...

  2. P4173 残缺的字符串 FFT匹配含有通配符的字符串

    传送门 文章目录 题意: 思路: 题意: 给你两个长度为m,nm,nm,n的串a,ba,ba,b,问你bbb串中每个长度为mmm的连续字串能否与aaa完全匹配,其中含有通配符∗*∗,输出每个位置的开头 ...

  3. P4173 残缺的字符串

    P4173 残缺的字符串 题意: 有A,B两个串,每个串都有通配符,问A为模板串,对于 B 的每一个位置 i,从这个位置开始连续 m 个字符形成的子串是否可能与 A 串完全匹配? 题解: 我们定义两个 ...

  4. BZOJ 4259: 残缺的字符串 [FFT]

    4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...

  5. 洛谷P1852 奇怪的字符串

    题目描述 输入两个01串,输出它们的最长公共子序列的长度 输入输出格式 输入格式: 一行,两个01串 输出格式: 最长公共子序列的长度 输入输出样例 输入样例#1: 复制 01010101010 00 ...

  6. 【BZOJ】4259: 残缺的字符串 FFT

    [题意]给定长度为m的匹配串B和长度为n的模板串A,求B在A中出现多少次.字符串仅由小写字母和通配符" * "组成,其中通配符可以充当任意一个字符.n<=3*10^5. [算 ...

  7. 洛谷P4199 万径人踪灭(manacher+FFT)

    传送门 题目所求为所有的不连续回文子序列个数,可以转化为回文子序列数-回文子串数 回文子串manacher跑一跑就行了,考虑怎么求回文子序列数 我们考虑,如果$S_i$是回文子序列的对称中心,那么只要 ...

  8. 洛谷P3952 时间复杂度【字符串】【模拟】

    题目描述 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂度,可他的编程老师实在不想一个一个检查小明的程序, 于是你的机会来啦!下面请你编写程序 ...

  9. 洛谷P3338:力(FFT)

    传送门 解析 算是比较适合的FFT入门题了吧 一个重要的trick: 当函数无法表示成卷积时,可以把函数翻转过来 然后调一调就又是卷积了 一个重要的注意事项是FFT的lim一定是两多项式相乘结果多项式 ...

最新文章

  1. 河科大c语言上机实验答案,2016年河南科技学院信息工程学院C语言上机编程考研复试题库...
  2. Objective-C @property和@synthesize
  3. boost::hana::trait用法的测试程序
  4. 如何看透借款人的隐形负债?
  5. jQuery.ajaxPrefilter()函数的使用
  6. android 屏幕横竖屏切换时生命周期运行详解,创建横屏layout,has no declaration in the base
  7. linux中var的作用,linux中var是什么意思
  8. 美团试水机器人送外卖;苹果向第三方提供 iPhone 维修零件;GoLand 2019.2.1 发布 | 极客头条...
  9. 误删除 Oracle 数据库数据的恢复方法
  10. win7上Android环境搭建以及调试
  11. 巨斧砍大树-sdut
  12. 研究领域、研究课题、研究方向三者的区别
  13. C语言 一行一行读取文件txt
  14. Xinlix原语OSERDESE2的使用和仿真
  15. 第五章 循环结构程序设计习题(2)
  16. 创建自己的盒子box_创建自己的
  17. dp备份错误:Mount request for any medium (blank or without protection)
  18. 【限定词习题】any 表“任何”
  19. jasper翻译_Jasper[杰斯帕,贾斯珀]的中文翻译及英文名意思
  20. 【名企招聘】4月27日19点,顺丰科技-带着岗位来招人啦

热门文章

  1. java搜索string_java – 在数组列表中搜索最常见的String
  2. cass字体_不动产 准备工作 第一步: 管理CASS码
  3. 中connect怎么用_烘焙中的各种酒,到底该怎么用?
  4. oracle 动态游标行数,oracle动态游标的简单实现方法
  5. c语言查单词小程序,【附源码】小程序初窥之简单查单词
  6. java 验证登陆_java登陆界面验证
  7. 宝塔mysql远程链接_宝塔apache启动失败:报错 AH00526: Syntax error on line 解决方案
  8. iar 看时序_IAR 硬件仿真查看运行时间
  9. [SpringSecurity]web权限方案_用户认证_自定义用户登录页面
  10. 《C++ Primer》14.2.1节练习