2017ACM ICPC Asia Regional-Daejeon H-Rock Paper Scissors[ FFT]

题目大意

给你两个字符串,N,M |N|>|M|,经过转换之后,问你,连续的一段,能够匹配上的最大元素个数。
n <1e5

题目分析

题目求区间内匹配数最大。考虑区间有n^2个,暴力做显然会T,所以这里考虑,用FFT
将第二个串反置,这样我们相邻位置的匹配,可以转化为,对应位置的匹配

如下图:


此时我们发现,最大匹配数 就是 i+j的系数

因此,我们分别求R,S,P的匹配,三次FFT之后将系数加起来,求一个最大值即可

代码分析

#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e6+50;
const double pi = acos(-1.0);
typedef long long ll;
struct Complex
{
	double x,y;
	Complex(double _x = 0,double _y=0)
	{
		x=_x; y=_y;
	}
	Complex operator +(const Complex &b) const
	{
		return Complex(x+b.x,y+b.y);
	}
	Complex operator -(const Complex &b) const
	{
		return Complex(x-b.x,y-b.y);
	}
	Complex operator * (const  Complex&b) const
	{
		return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
	}
}a[maxn],b[maxn];
int S,T,n,m,L,R[maxn],ans[maxn]; //S 表示A序列的长度 ,T表示B序列的长度
//n 表示 >=S+T 的2的幂次 L表示幂次 R数组是旋转数组,ans答案数组
ll F[maxn];
double f[maxn][3],g[maxn][3];// f,g数组是整数转化为实数的数组 
char x[maxn],y[maxn];
void FFT(Complex a[],int opt)
{
	for(int i=0;i<n;i++) if(i<R[i]) swap(a[i],a[R[i]]);// 翻转数组
	for(int k=1;k<n;k<<=1)
	{
		Complex wn = Complex(cos(pi/k),opt*sin(pi/k));
		for(int i=0;i<n;i+=(k<<1))
		{
			Complex w = Complex(1,0);
			for(int j=0;j<k;j++,w=w*wn)
			{
				Complex x = a[i+j],y = w*a[i+j+k];
				a[i+j] = x+y;
				a[i+j+k] = x-y;
			}
		}
	}
} 
void calc(int opt)
{
	FFT(a,1);
	FFT(b,1);
	for(int i=0;i<=n;i++) a[i]=a[i]*b[i];
	FFT(a,-1);
	for(int i=0;i<=n;i++) F[i] = (ll) (a[i].x/n+0.5)*opt;
	
}
int main()
{
	
	scanf("%d%d",&S,&T);
	S--,T--;
	scanf("%s%s",x,y);
	for(int i=0;i<=S;i++)
	{
		if(x[i]=='R') f[i][0] = 1.0;
		if(x[i]=='S') f[i][1] = 1.0;
		if(x[i]=='P') f[i][2] = 1.0;
	}
	for(int i=0;i<=T;i++)
	{
		if(y[i]=='R') g[T-i][1] = 1.0;
		if(y[i]=='S') g[T-i][2] = 1.0;
		if(y[i]=='P') g[T-i][0] = 1.0;
	}
//	for(int i=0;i<=T;i++) scanf("%lf",&g[i]);
	m=T+S; L=0;
	for(n=1;n<=m;n<<=1) L++;
	for(int i=0;i<n;i++) R[i] = (R[i>>1]>>1)|((i&1)<<(L-1));
	for(int kase=0;kase<3;kase++)
	{
		for(int i=0;i<=n;i++)
		{
			a[i]= Complex(1.0*f[i][kase],0.0);
			b[i]= Complex(1.0*g[i][kase],0.0);
		}
		calc(1);
		for(int i=0;i<=S+T;i++) {
			ans[i]+=F[i];
		//	printf("%lld ",F[i]);
		}
	//	printf("\n");
	}
	int allans=0;
	for(int i=T;i<=S+T;i++) allans= max(allans,ans[i]);
	printf("%d\n",allans); 
	return 0;
} 

/*
12 4
PPPRRRRRRRRR
RSSS

12 4
RRRRRRRRRSSS
RRRS



*/
全部评论

相关推荐

10-15 16:27
门头沟学院 C++
LeoMoon:建议问一下是不是你给他付钱😅😅
点赞 评论 收藏
分享
AaronRuan:看到了好多开奖了,不知道为啥自己也有点激动,真的替你们感到高兴啊
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务