题目大意:

两个带通配符的字符串\(a,b\),求\(a\)在\(b\)中出现的位置

字符串长度\(\le 300000\)

考虑魔改一发\(kmp\),发现魔改不出来

于是考虑上网搜题解

然后考虑\(ntt\),发现两个串匹配需要满足\(\sum\limits_{i=0}^{n-1}(a_i-b_i)=0\)

发现不太对,可能有正有负相消等于\(0\),我们加上平方\(\sum\limits_{i=0}^{n-1}(a_i-b_i)^2=0\)

再考虑通配符,我们可以设通配符的价值为\(0\),然后变形一下\(\sum\limits_{i=0}^{n-1}a_i*b_i*(a_i-b_i)^2=0\)

展开得到\(\sum\limits_{i=0}^{n-1}a_i^3*b_i-2a_i^2*b_i^2+a_i*b_i^3\)

我们可以把这三项分开考虑

对于其中一项\(\sum\limits_{i=0}^{n-1}a_i^3*b_i\)

设\(a^{'}\)为\(a\)翻转,\(j=n-i-1\),答案为\(\sum\limits_{i=0}^{n-1}a_j^{'3}*b_i\)

然后卷起来,判断卷完之后\(i=(m-1\sim n-1)\)哪个系数是零,把\(i-m+2\)加入答案

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
inline int read()
{
int x=0;char ch,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=0,ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
const int N=3e5+10,p=998244353,g=3,gi=332748118;
int n,m,limit,len;
char a[N],b[N];
int pos[N<<2];
int ret[N],num;
int a1[N<<2],b1[N<<2],c[N<<2];
inline int fast(int x,int k)
{
int ret=1;
while(k)
{
if(k&1) ret=ret*x%p;
x=x*x%p;
k>>=1;
}
return ret;
}
inline void ntt(int *a,int inv)
{
for(int i=0;i<limit;++i)
if(i<pos[i]) swap(a[i],a[pos[i]]);
for(int mid=1;mid<limit;mid<<=1)
{
int Wn=fast(inv?g:gi,(p-1)/(mid<<1));
for(int r=mid<<1,j=0;j<limit;j+=r)
{
int w=1;
for(int k=0;k<mid;++k,w=w*Wn%p)
{
int x=a[j+k],y=w*a[j+k+mid]%p;
a[j+k]=(x+y)%p;
a[j+k+mid]=(x-y)%p;
if(a[j+k+mid]<0) a[j+k+mid]+=p;
}
}
}
if(inv) return;
inv=fast(limit,p-2);
for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
}
inline void work(int *a,int *b,int opt)
{
ntt(a,1);ntt(b,1);
for(int i=0;i<limit;++i) c[i]=c[i]+a[i]*b[i]*opt;
}
inline void main()
{
m=read(),n=read();
scanf("%s%s",a,b);
for(int i=0;i<m;++i)
{
if(a[i]=='*') a[i]=0;
else a[i]=a[i]-'a'+1;
}
for(int i=0;i<n;++i)
{
if(b[i]=='*') b[i]=0;
else b[i]=b[i]-'a'+1;
}
reverse(a,a+m);
for(limit=1;limit<=n+m;limit<<=1) ++len;
for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
for(int i=0;i<m;++i) a1[i]=a[i]*a[i]*a[i];
for(int i=0;i<n;++i) b1[i]=b[i];
work(a1,b1,1);
for(int i=0;i<limit;++i) a1[i]=b1[i]=0;
for(int i=0;i<m;++i) a1[i]=a[i]*a[i];
for(int i=0;i<n;++i) b1[i]=b[i]*b[i];
work(a1,b1,-2);
for(int i=0;i<limit;++i) a1[i]=b1[i]=0;
for(int i=0;i<m;++i) a1[i]=a[i];
for(int i=0;i<n;++i) b1[i]=b[i]*b[i]*b[i];
work(a1,b1,1);
ntt(c,0);
for(int i=m-1;i<n;++i)
{
if(!c[i]) ret[++num]=i-m+2;
}
printf("%lld\n",num);
for(int i=1;i<=num;++i) printf("%lld ",ret[i]);
}
}
signed main()
{
red::main();
return 0;
}

洛谷P4173 残缺的字符串的更多相关文章

  1. 洛谷 P4173 残缺的字符串 (FFT)

    题目链接:P4173 残缺的字符串 题意 给定长度为 \(m\) 的模式串和长度为 \(n\) 的目标串,两个串都带有通配符,求所有匹配的位置. 思路 FFT 带有通配符的字符串匹配问题. 设模式串为 ...

  2. 洛谷P4173 残缺的字符串(FFT)

    传送门 话说为什么字符串会和卷积扯上关系呢……到底得脑洞大到什么程度才能想到这种东西啊……大佬太珂怕了…… 因为通配符的关系,自动机已经废了 那么换种方式考虑,如果两个字符串每一位对应的编码都相等,那 ...

  3. 洛谷 P4173 残缺的字符串

    (不知道xjb KMP可不可以做的说) (假设下标都以0开头) 对于有一定偏移量的序列的 对应位置 匹配或者数值计算的题,这里是有一种套路的,就是把其中一个序列翻转过来,然后卷积一下,所得到的新序列C ...

  4. Luogu P4173 残缺的字符串-FFT在字符串匹配中的应用

    P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C ...

  5. P4173 残缺的字符串(FFT字符串匹配)

    P4173 残缺的字符串(FFT字符串匹配) P4173 解题思路: 经典套路将模式串翻转,将*设为0,设以目标串的x位置匹配结束的匹配函数为\(P(x)=\sum^{m-1}_{i=0}[A(m-1 ...

  6. BZOJ1856或洛谷1641 [SCOI2010]生成字符串

    BZOJ原题链接 洛谷原题链接 可以将\(1\)和\(0\)的个数和看成是\(x\)轴坐标,个数差看成\(y\)轴坐标. 向右上角走,即\(x\)轴坐标\(+1\),\(y\)轴坐标\(+1\),表示 ...

  7. 卡特兰数 洛谷P1641 [SCOI2010]生成字符串

    卡特兰数 参考博客 介绍 卡特兰数为组合数学中的一种特殊数列,用于解决一类特殊问题 设\(f(n)\)为卡特兰数的第n项 其通项公式为 \[f(n)=\frac{2n\choose n}{n+1} \ ...

  8. 洛谷 P1641 [SCOI2010]生成字符串

    洛谷 这题一看就是卡塔兰数. 因为\(cnt[1] \leq cnt[0]\),很显然的卡塔兰嘛! 平时我们推导卡塔兰是用一个边长为n的正方形推的, 相当于从(0,0)点走到(n,n)点,向上走的步数 ...

  9. 洛谷P1852 奇怪的字符串

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

随机推荐

  1. Noip刷题计划

    写在前面 去年也想刷10年NOIP来着..结果刷到13年就没动力了233... 今年一定要完成目标啊!! "愿你明日重生,醒时心存冬阳" 2018年 题目 首次得分 出错原因 考点 ...

  2. Python程序中的进程操作-进程间数据共享(multiprocess.Manager)

    目录 一.进程之间的数据共享 1.1 Manager模块介绍 1.2 Manager例子 一.进程之间的数据共享 展望未来,基于消息传递的并发编程是大势所趋 即便是使用线程,推荐做法也是将程序设计为大 ...

  3. celery定时器

    Celery 1.什么是Clelery Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统 专注于实时处理的异步任务队列 同时也支持任务调度 Celery架构 Celery的架构由三部分组 ...

  4. Mysql - 存储过程 - 定时删表

    在工业监控里面, 需要对每天的数据, 进行记录, 时间长了之后, 数据库很容易撑爆. 这时候, 如果允许, 可以对之前的数据进行一次清除, 只记录几个月内的数据. delimiter $ DROP P ...

  5. swoole中使用task进程异步的处理耗时任务

    我们知道,swoole中有两大进程,分别是 master 主进程和 manager 管理进程. 其中 master 主进程中会有一个主 reactor 线程和多个 reactor 线程,主要的作用就是 ...

  6. _NtCreateDebugObject(ntoskrnl.exe)函数逆向分析

    该函数由 DbgUiConnectToDbg(ntdll.dll)函数 调用. 其调用时传入的参数如下: 函数作用:初始化被调试的内核对象,将被调试对象句柄放入调试对象的 [fs:f24]处. 1.现 ...

  7. Protobuffer学习文档

    官方EN:https://developers.google.com/protocol-buffers/docs/pythontutorial 中文:https://cloud.tencent.com ...

  8. Python爬取十四万条书籍信息告诉你哪本网络小说更好看

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: TM0831 PS:如有需要Python学习资料的小伙伴可以加点击 ...

  9. 2-2-for循环

    重复执行某些代码 每次执行的时候有个数字在变化 常用格式 <script> for(var i=0; i<3; i++){alert(i); } </script> 1) ...

  10. 边框渐变背景色border-image: linear-gradient()

    前言 前几天无意间听说了边框渐变背景色,网上查了下,没有发现与之有关的介绍,亲测之后和大家分享一下. 边框渐变背景色 写法 border-image: gradient top right botto ...