4503: 两个串

将s2串倒过来,把?看成0,

很容易把式子化成f[i] = ∑(s1[i] - s2[len2+i-j]))^2*s2[len2+i-j]

然后展开得到俩个卷积与一个常数,然后上fft即可

c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x ; i <= y;++ i)
typedef long long ll;
using namespace std;
template<typename T>inline void read(T&x)
{
	x = 0;char c;int sign = 1;
	do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
	do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
	x *= sign;
}

const int g = 3,mod = 998244353,N = 4e5+500;

int R[N],len1,len2,n,m,L;

inline int quick_pow(int x,int y)
{
	int ans = 1;
	while(y)
	{
		if(y & 1) ans = 1ll * ans * x % mod;
		x = 1ll * x * x % mod;
		y >>= 1;
	}
	return ans;
}

inline void ntt(ll*a,int f)
{
	rep(i,0,n - 1) if(i < R[i]) swap(a[i],a[R[i]]);
	for(register int i = 1; i < n ; i <<= 1)
	{
		ll wn = quick_pow(g,(mod - 1)/(i << 1));
		if(!(~f)) wn = quick_pow(wn,mod - 2);
		for(register int j = 0; j < n ; j += (i << 1))
		{
			ll w = 1;
			for(register int k = 0;k < i ;++k,w = w * wn % mod)
			{
				ll x = a[j + k],y = w * a[i + j + k] % mod;
				a[j + k] = ((x + y) % mod + mod) % mod;
				a[i + j + k] = ((x - y) % mod + mod) % mod;
			}
		}
	}
	
	if(f == -1)
	{
		int inv = quick_pow(n,mod - 2);
		rep(i,0,n - 1) a[i] = a[i] * inv % mod;
	}
} 

char s1[N],s2[N];
ll a1[N],a2[N],b1[N],b2[N],sum,ans;

int main()
{
	scanf("%s",s1);
	scanf("%s",s2);
	n = strlen(s1); m = strlen(s2);
	len1 = n; len2 = m;
	
	for(int i = 0,j = m - 1;i < j;++i,--j) swap(s2[i],s2[j]);
	
	rep(i,0,n - 1) s1[i] = s1[i] - 'a' + 1;
	rep(i,0,m - 1) s2[i] = s2[i] == '?'? 0 : s2[i] - 'a' + 1;
	
	rep(i,0,m - 1) sum = sum + s2[i] * s2[i] * s2[i];
	rep(i,0,n - 1) a1[i] = s1[i] * s1[i]; rep(i,0,n - 1) a2[i] = s1[i];
	rep(i,0,m - 1) b1[i] = s2[i]; rep(i,0,m - 1) b2[i] = s2[i] * s2[i];
	
	m = n + m - 2; 
	for(n = 1; n <= m ; n <<= 1,++L);
	rep(i,0,n - 1) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
	ntt(a1,1); ntt(a2,1); ntt(b1,1); ntt(b2,1);
	
	rep(i,0,n - 1) a1[i] = a1[i] * b1[i] % mod;
	rep(i,0,n - 1) a2[i] = a2[i] * b2[i] % mod;
	
	ntt(a1,-1); ntt(a2,-1);
	
	len2 --; len1--;
	rep(i,len2,len1) if((a1[i] - 2 * a2[i] + sum) % mod == 0) ans++;
	
	cout << ans << endl;
	rep(i,len2,len1) if((a1[i] - 2 * a2[i] + sum) % mod == 0) printf("%d\n",i - len2);
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值