题目大意:

两个带通配符的字符串\(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. IT人的立功,立言,立德三不朽

    最近几个月很忙,忙着当奶爸,忙着做加班狗,忙着补裤裆学技术……以至于快忘了要思考人生了! 古人立志穷极一生追求“立德”,“立功”,“立言”,以求不朽,为万世所景仰,为后人所传颂,实现人生的意义.立德者 ...

  2. Istio修改IngressGateway网络类型

    ingressgateway的默认网络类型是LoadBanlancer,在没有外部负载均衡的情况下可以修改为NodePort. 1.修改 kubectl patch service istio-ing ...

  3. js获取url参数值的方法总结

    1.方式一:通过字符串截取的方式获取参数值: 1).函数一:获取URL中的参数名及参数值的集合 /** * [获取URL中的参数名及参数值的集合] * 示例URL:http://htmlJsTest/ ...

  4. 安全性测试:OWASP ZAP 2.8 使用指南(一):安全测试基础及ZAP下载、安装

    概览 本文意在对于OWASP's Zed Attack Proxy(ZAP)软件做一个基本使用指南介绍. ZAP是一个用于实施安全性测试的工具,即使没有很强的安全测试背景也可以很好的使用. 为了达到这 ...

  5. 转Ubuntu 16.04 创建无线热点

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/ac_dao_di/article/deta ...

  6. go-函数和错误处理

    函数基本语法 func 函数名(形参列表)(返回值列表){ 执行语句 return 返回值列表 }//返回值可以没有可以有多个可以有一个 包 引入 为了解决两个程序员取得函数名同名的情况 原理 本质就 ...

  7. webpack资源处理

    使用上篇已谈过,这篇纯代码!!~~ <!DOCTYPE html> <html lang="en"> <head> <meta chars ...

  8. SSM定时任务(spring3.0)

    SSM定时任务主要分为两部分 1.applicationContext.xml配置文件设置 设置如下: 在xmlns中添加:xmlns:task="http://www.springfram ...

  9. Java生鲜电商平台-Java后端生成Token架构与设计详解

    Java生鲜电商平台-Java后端生成Token架构与设计详解 目的:Java开源生鲜电商平台-Java后端生成Token目的是为了用于校验客户端,防止重复提交. 技术选型:用开源的JWT架构. 1. ...

  10. 图片在DIV里边水平垂直居中

    图片在一个DIV中要垂直水平居中,首先定义一个DIV .wrap{ width: 600px; height: 400px; border: 1px #000 solid; } 插入图片 <di ...