传送门

题意简述:给两个字符串s,ts,ts,t,ttt中可能有通配符,问ttt在sss出现的次数和所有位置。


思路:一道很熟悉的题,跟bzoj4259bzoj4259bzoj4259差不多的。

然后把每个字符串的字符投射成数值(′a′'a'′a′ ~ ′z′→1'z'\rightarrow1′z′→1~262626,′?′→0'?'\rightarrow0′?′→0)。

考虑对于两个数(a,b)(a,b)(a,b)设计一个distdistdist函数dista,b=b(a−b)2dist_{a,b}=b(a-b)^2dista,b​=b(a−b)2那么

两个等长的字符串S,TS,TS,T的DistDistDist值DistS,T=∑i=0∣S∣−1distSi,TIDist_{S,T}=\sum_{i=0}^{|S|-1}dist_{S_i,T_I}DistS,T​=∑i=0∣S∣−1​distSi​,TI​​

显然如果DistS,T=0Dist_{S,T}=0DistS,T​=0表示S,TS,TS,T可以匹配。

那么考虑把给出的串TTT反过来,这样DistS,TDist_{S,T}DistS,T​就变成了卷积的形式,即ci=∑(aj−bi−j)2bi−jc_i=\sum(a_j-b_{i-j})^2b_{i-j}ci​=∑(aj​−bi−j​)2bi−j​,由于直接做不是很好做因此我们把这个式子拆开变成:ci=∑aj2bi−j−2ajbi−j2+bi−j3c_i=\sum a_j^2b_{i-j}-2a_jb_{i-j}^2+b_{i-j}^3ci​=∑aj2​bi−j​−2aj​bi−j2​+bi−j3​前面两项用两次fftfftfft搞定,最后一项的加和是一个定值,全部算出来之后加起来就是DistDistDist每一项的值。

时间复杂度O(nlogn)O(nlog_n)O(nlogn​)

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e5+5;
struct cp{
	double x,y;
	friend inline cp operator+(const cp&a,const cp&b){return (cp){a.x+b.x,a.y+b.y};}
	friend inline cp operator-(const cp&a,const cp&b){return (cp){a.x-b.x,a.y-b.y};}
	friend inline cp operator*(const cp&a,const cp&b){return (cp){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
	friend inline cp operator/(const cp&a,const double&b){return (cp){a.x/b,a.y/b};}
};
typedef long long ll;
int tim,lim;
vector<int>pos;
vector<cp>A,B;
inline void init(const int&up){
	lim=1,tim=0;
	while(lim<=up)lim<<=1,++tim;
	pos.resize(lim),A.resize(lim),B.resize(lim),pos[0]=0;
	for(ri i=0;i<lim;++i)pos[i]=(pos[i>>1]>>1)|((i&1)<<(tim-1));
}
const double pi=acos(-1.0);
inline void fft(vector<cp>&a,const int&type){
	for(ri i=0;i<lim;++i)if(i<pos[i])swap(a[i],a[pos[i]]);
	for(ri mid=1;mid<lim;mid<<=1){
		cp wn=(cp){cos(pi/mid),sin(pi/mid)*type},w,a0,a1;
		for(ri j=0,len=mid<<1;j<lim;j+=len){
			w=(cp){1,0};
			for(ri k=0;k<mid;++k,w=w*wn)a0=a[j+k],a1=a[j+k+mid]*w,a[j+k]=a0+a1,a[j+k+mid]=a0-a1;
		}
	}
	if(type==-1)for(ri i=0;i<lim;++i)a[i]=a[i]/lim;
}
struct poly{
	vector<cp>a;
	poly(int k=0,cp x=(cp){0,0}){a.resize(k+1),a[k]=x;}
	inline cp&operator[](const int&k){return a[k];}
	inline const cp&operator[](const int&k)const{return a[k];}
	inline int deg()const{return a.size()-1;}
	inline poly extend(const int&k){poly ret=*this;return ret.a.resize(k+1),ret;}
	friend inline poly operator*(const poly&a,const poly&b){
		int n=a.deg(),m=b.deg();
		poly ret;
		init(n+m);
		for(ri i=0;i<=n;++i)A[i]=a[i];
		for(ri i=0;i<=m;++i)B[i]=b[i];
		for(ri i=n+1;i<lim;++i)A[i]=(cp){0,0};
		for(ri i=m+1;i<lim;++i)B[i]=(cp){0,0};
		fft(A,1),fft(B,1);
		for(ri i=0;i<lim;++i)A[i]=A[i]*B[i];
		return fft(A,-1),ret.a=A,ret;
	}
};
char s[N],t[N];
int n,m;
ll val[N];
inline void solve1(){
	poly a(n),b(m);
	for(ri i=0;i<=n;++i)a[i].x=(s[i]-'a'+1)*(s[i]-'a'+1),a[i].y=0;
	for(ri i=0;i<=m;++i)b[i].x=t[i]=='?'?0:t[i]-'a'+1,b[i].y=0;
	reverse(b.a.begin(),b.a.end());
	a=a*b;
	for(ri i=0,j=m;j<=n;++i,++j)val[i]+=(ll)(a[j].x+0.5);
}
inline void solve2(){
	poly a(n),b(m);
	for(ri i=0;i<=n;++i)a[i].x=s[i]-'a'+1,a[i].y=0;
	for(ri i=0;i<=m;++i)b[i].x=t[i]=='?'?0:(t[i]-'a'+1)*(t[i]-'a'+1),b[i].y=0;
	reverse(b.a.begin(),b.a.end());
	a=a*b;
	for(ri i=0,j=m;j<=n;++i,++j)val[i]-=(ll)(a[j].x+0.5)*2;
}
inline void solve3(){
	ll sum=0;
	for(ri i=0,x;i<=m;++i)x=t[i]=='?'?0:t[i]-'a'+1,sum+=(ll)x*x*x;
	for(ri i=0,j=m;j<=n;++i,++j)val[i]+=sum;
}
int main(){
	scanf("%s%s",s,t),n=strlen(s)-1,m=strlen(t)-1;
	solve1(),solve2(),solve3();
	vector<int>ans;
	for(ri i=0,j=m;j<=n;++i,++j)if(!val[i])ans.push_back(i);
	cout<<ans.size()<<'\n';
	for(ri i=0;i<ans.size();++i)cout<<ans[i]<<'\n';
	return 0;
}

2019.02.06 bzoj4503: 两个串(fft)的更多相关文章

  1. bzoj4503: 两个串 bitset

    目录 题目链接 题解 代码 题目链接 bzoj4503: 两个串 题解 暴一发bitset f[i][j] 表示 S[1..i] 是否有个后缀能匹配 T[1..j] 那么假设 S[i+1] 能匹配 T ...

  2. 【BZOJ4503】两个串 FFT

    [BZOJ4503]两个串 Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字 ...

  3. 【bzoj4259/bzoj4503】残缺的字符串/两个串 FFT

    bzoj4259 题目描述 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有 ...

  4. BZOJ4259: 残缺的字符串 & BZOJ4503: 两个串

    [传送门:BZOJ4259&BZOJ4503] 简要题意: 给出两个字符串,第一个串长度为m,第二个串长度为n,字符串中如果有*字符,则代表当前位置可以匹配任何字符 求出第一个字符串在第二个字 ...

  5. BZOJ 4503: 两个串 [FFT]

    4503: 两个串 题意:兔子们在玩两个串的游戏.给定两个只含小写字母的字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有"?"字符,这个字符可以匹 ...

  6. BZOJ4503: 两个串

    Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字符. Input 两行两个字 ...

  7. BZOJ4503 两个串 多项式 FFT

    题目传送门 - BZOJ4503 题意概括 给定两个字符串S和T,回答T在S中出现了几次,在哪些位置出现.注意T中可能有?字符,可以匹配任何字符. 题解 首先,假装你已经知道了这是一道$FFT$题. ...

  8. 【bzoj4503】 两个串 FFT

    $FFT$套路题(然而我看错题了) 我们考虑化一下式子. 设当前比较的两个部分为$S[i....i+|T|-1]$和$T[0....|T|-1]$. 我们对串$T$中出现问号的位置全部赋值为$0$. ...

  9. BZOJ4503 两个串 【fft】

    题目链接 BZOJ4503 题解 水水题. 和残缺的字符串那题几乎是一样的 同样转化为多项式 同样TLE 同样要手写一下复数才A #include<algorithm> #include& ...

随机推荐

  1. 安卓操作系统版本(Version)与应用程序编程接口等级(Application Programming Interface Level)对照表

    Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑. 使用Android API,可以在Java环境开发App,编译.打包后可在Android系统 ...

  2. 【Linux 进程】fork函数详解

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同, ...

  3. 32-java 里面list的问题

    申明一个对象时,一般前的类型需要申明的: List list1 = new ArrayList<Edge1>();    这个不能调用对象的属性 和 List<Edge1> l ...

  4. TF30063:没有访问xxx的权限 vs2017

    凭据什么的都删掉了,还是无法连接上,最后同事用一种方法o(╥﹏╥)o,先登录vs2015的tfs账号,然后再vs2017上面登录tfs账号即可解决.PS:网上很多文章都是抄的,这个Bug真TM恶心.

  5. 如何提高php应用的性能?

    1. 如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍.2.$row[’id’] 的速度是$row[id]的7倍.3.echo 比 print快,并且使用echo的 ...

  6. oracle 使用exp命令 sys用户登录 导出表存为dmp文件

    在cmd下面,使用exp命令,格式为 exp \"sys/123456@dbname as sysdba\" file=d:\dmp\test.dmp tables=sys.tes ...

  7. C++中find_if

    总结:find_if针对查找的对象中包含指针需要进行比较 find则更偏向于普通的数值或者字符比较 两者都可以应用于自定义的类,只需在类中重载==运载符 函数调用符()说白了其实就是代替函数指针,调用 ...

  8. angular2.0学习笔记7.echarts 地图(type:'map')slice undifined 出错问题

    在 项目\node_modules\echarts\lib\chart\map.js文件头部 ... ... require("../coord/geo/geoCreator"); ...

  9. PAT 1081 检查密码(15) (代码+思路)

    1081 检查密码(15 分) 本题要求你帮助某网站的用户注册模块写一个密码合法性检查的小功能.该网站要求用户设置的密码必须由不少于6个字符组成,并且只能有英文字母.数字和小数点 .,还必须既有字母也 ...

  10. js的日期格式判断

    var reg = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/; var str = (new Date).toLocaleString() ...