FFT匹配字符串
无匹配符
void FFT_Match(char *s1,char *s2,int m,int n){
for(int i=0;i<m;i++){
a[i].real()=s1[i]-'a'+1;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
b[i].real()=s2[i]-'a'+1;
}
reverse(a,a+m);//反转匹配字符串
double T=0;
for(int i=0;i<m;i++){
T+=a[i].real()*a[i].real();
}
double b2[maxN];
b2[0]=b[0].real()*b[0].real();
for(int i=1;i<n;i++){
b2[i]=b2[i-1]+b[i].real()*b[i].real();
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
a[i]=a[i]*b[i];
}
FFT(a,len,-1);//点值化为系数表示
for(int k=0;k<=n-m;k++){
double p=k>0? T+b2[k+m-1]-b2[k-1]-2*(int)(a[k+m-1].real()/len+0.5)
:T+b2[k+m-1]-2*(int)(a[k+m-1].real()/len+0.5);
if(p==0)
printf("%d ",k);
}
}
有匹配符
void FFT_Match_tongpei(char *s1,char *s2,int m,int n){
complex<double> p[maxN];
reverse(s1,s1+m);//反转匹配字符串
memset(A,0,len*sizeof(long long));
memset(B,0,len*sizeof(long long));
memset(p,0,len*sizeof(long long));
for(int i=0;i<m;i++){
A[i]=(s1[i]!='#')? (s1[i]-'a'+1):0;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
B[i]=(s2[i]!='#')? (s2[i]-'a'+1):0;
}
for(int i=0;i<len;i++){
a[i].real()=A[i]*A[i]*A[i];
a[i].imag()=0;
b[i].real()=B[i];
b[i].imag()=0;
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}
for(int i=0;i<len;i++){
a[i].real()=A[i];
a[i].imag()=0;
b[i].real()=B[i]*B[i]*B[i];
b[i].imag()=0;
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}for(int i=0;i<len;i++){
a[i].real()=A[i]*A[i];
a[i].imag()=0;
b[i].real()=B[i]*B[i];
b[i].imag()=0;
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]-a[i]*b[i]-a[i]*b[i];
}
FFT(p,len,-1);
for(int k=0;k<=n-m;k++){
if((int)(p[k+m-1].real()/len+0.5)==0)
printf("%d ",k);
}
}
完整代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <complex> //复数模板头文件
using namespace std;
const int maxN=100010;
const double pi=3.1415926;
void FFT(complex<double> *a,int n,int inv);
int len,n1,n2,cnt,rev[maxN],c[maxN],sign=1;//合成函数
void trans(int c[],int n);
void FFT_Match(char *s1,char *s2,int m,int n);
void FFT_Match_tongpei(char *s1,char *s2,int m,int n);
int A[maxN],B[maxN];
complex<double> a[maxN],b[maxN];
int main()
{
char s1[maxN],s2[maxN];
while(~scanf("%s%s",s1,s2)){
len=1;
n1=strlen(s1);
n2=strlen(s2);
while(len<n1+n2)len<<=1;//将n化作c的系数值,n为2的倍数;
//FFT_Match(s2,s1,n2,n1);//注意这里前者为匹配字符串模板
FFT_Match_tongpei(s2,s1,n2,n1);
memset(a, 0 , (len+10)*sizeof(complex<double>));
memset(b, 0 , (len+10)*sizeof(complex<double>));
}
return 0;
}
void FFT(complex<double> *a,int n,int inv){
int bit=0;
while((1<<bit)<n)bit++;
for(int i=0;i<n;i++){ //为每一个值作下标的颠倒
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
if(i<rev[i])//防止又转换回来
swap(a[i],a[rev[i]]);
}//下标颠倒之后a[i]代表基本值,len为2时加并一步步叠加
for(int mid=1;mid<n;mid<<=1){ //从最底层开始叠加
complex<double> wn(cos(pi/mid),inv*sin(pi/mid));//每一层的单位根
for(int i=0;i<n;i+=mid<<1){//给每一层分组,i是每组起始位置
complex<double> w(1,0);//
for(int j=0;j<mid;j++){//组内运算
complex<double> x=a[i+j],y=w*a[i+j+mid];
a[i+j]=x+y;a[i+j+mid]=x-y;
w*=wn;//运算时取实数部分
}
}
}
}
void FFT_Match(char *s1,char *s2,int m,int n){
for(int i=0;i<m;i++){
a[i].real()=s1[i]-'a'+1;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
b[i].real()=s2[i]-'a'+1;
}
reverse(a,a+m);//反转匹配字符串
double T=0;
for(int i=0;i<m;i++){
T+=a[i].real()*a[i].real();
}
double b2[maxN];
b2[0]=b[0].real()*b[0].real();
for(int i=1;i<n;i++){
b2[i]=b2[i-1]+b[i].real()*b[i].real();
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
a[i]=a[i]*b[i];
}
FFT(a,len,-1);//点值化为系数表示
for(int k=0;k<=n-m;k++){
double p=k>0? T+b2[k+m-1]-b2[k-1]-2*(int)(a[k+m-1].real()/len+0.5)
:T+b2[k+m-1]-2*(int)(a[k+m-1].real()/len+0.5);
if(p==0)
printf("%d ",k);
}
}
void FFT_Match_tongpei(char *s1,char *s2,int m,int n){
complex<double> p[maxN];
reverse(s1,s1+m);//反转匹配字符串
memset(A,0,len*sizeof(long long));
memset(B,0,len*sizeof(long long));
memset(p,0,len*sizeof(long long));
for(int i=0;i<m;i++){
A[i]=(s1[i]!='#')? (s1[i]-'a'+1):0;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
B[i]=(s2[i]!='#')? (s2[i]-'a'+1):0;
}
for(int i=0;i<len;i++){
a[i].real()=A[i]*A[i]*A[i];
a[i].imag()=0;
b[i].real()=B[i];
b[i].imag()=0;
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}
for(int i=0;i<len;i++){
a[i].real()=A[i];
a[i].imag()=0;
b[i].real()=B[i]*B[i]*B[i];
b[i].imag()=0;
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}for(int i=0;i<len;i++){
a[i].real()=A[i]*A[i];
a[i].imag()=0;
b[i].real()=B[i]*B[i];
b[i].imag()=0;
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]-a[i]*b[i]-a[i]*b[i];
}
FFT(p,len,-1);
for(int k=0;k<=n-m;k++){
if((int)(p[k+m-1].real()/len+0.5)==0)
printf("%d ",k);
}
}
石头剪刀布问题
题设:想哥给出一个长度为n的序列,而叶姐给出长度为m的序列。1≤m<n≤100,0001≤m<n≤100,000。叶姐显然有特权,她可以选择跳过想哥序列的一段开头,才开始将RSP序列进行匹配,以寻求从这一位置开始最多获胜次数。
请你帮叶姐求出这一次数,这就是想哥请17级吃饭的次数。显然,R胜S,S胜P,P胜R。
解:FFT分别匹配三种情况
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <complex> //复数模板头文件
using namespace std;
const int maxN=1000000;
const double pi=3.1415926;
void FFT(complex<double> *a,int n,int inv);
int len,n1,n2,cnt,rev[maxN],c[maxN],sign=1;//合成函数
void trans(int c[],int n);
void FFT_Match(char *s1,char *s2,int m,int n);
void FFT_Match_tongpei(char *s1,char *s2,int m,int n);
int A[maxN],B[maxN];
complex<double> a[maxN],b[maxN];
complex<double> p[maxN];
int main()
{
char s1[maxN],s2[maxN];
scanf("%d%d",&n1,&n2);
scanf("%s",s1);
scanf("%s",s2);
len=1;
while(len<n1+n2)len<<=1;//将n化作c的系数值,n为2的倍数;
FFT_Match_tongpei(s2,s1,n2,n1);
//memset(a, 0 , (len+10)*sizeof(complex<double>));
//memset(b, 0 , (len+10)*sizeof(complex<double>));
return 0;
}
void FFT(complex<double> *a,int n,int inv){
int bit=0;
while((1<<bit)<n)bit++;
for(int i=0;i<n;i++){ //为每一个值作下标的颠倒
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
if(i<rev[i])//防止又转换回来
swap(a[i],a[rev[i]]);
}//下标颠倒之后a[i]代表基本值,len为2时加并一步步叠加
for(int mid=1;mid<n;mid<<=1){ //从最底层开始叠加
complex<double> wn(cos(pi/mid),inv*sin(pi/mid));//每一层的单位根
for(int i=0;i<n;i+=mid<<1){//给每一层分组,i是每组起始位置
complex<double> w(1,0);//
for(int j=0;j<mid;j++){//组内运算
complex<double> x=a[i+j],y=w*a[i+j+mid];
a[i+j]=x+y;a[i+j+mid]=x-y;
w*=wn;//运算时取实数部分
}
}
}
}
void FFT_Match_tongpei(char *s1,char *s2,int m,int n){
reverse(s1,s1+m);//反转匹配字符串
//匹配R->S
for(int i=0;i<m;i++){
A[i]=(s1[i]=='R')? 1:0;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
B[i]=(s2[i]=='S')? 1:0;
}
for(int i=0;i<len;i++){
a[i]=complex<double>(A[i],0);
b[i]=complex<double>(B[i],0);
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}
//匹配S->P
for(int i=0;i<m;i++){
A[i]=(s1[i]=='S')? 1:0;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
B[i]=(s2[i]=='P')? 1:0;
}
for(int i=0;i<len;i++){
a[i]=complex<double>(A[i],0);
b[i]=complex<double>(B[i],0);
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}
//匹配P->R
for(int i=0;i<m;i++){
A[i]=(s1[i]=='P')? 1:0;//减小字符串的匹配数,由字符串的范围来减
}
for(int i=0;i<n;i++){
B[i]=(s2[i]=='R')? 1:0;
}
for(int i=0;i<len;i++){
a[i]=complex<double>(A[i],0);
b[i]=complex<double>(B[i],0);
}
FFT(a,len,1);//系数化为点值表示
FFT(b,len,1);
for(int i=0;i<len;i++){
p[i]=p[i]+a[i]*b[i];
}
FFT(p,len,-1);
int minc=0;
for(int k=0;k<=n-m;k++){
//printf("%d=%d ",k,(int)(p[k+m-1].real()/len+0.5));
if((int)(p[k+m-1].real()/len+0.5)>minc)
minc=(int)(p[k+m-1].real()/len+0.5);
}
printf("%d",minc);
}