Codeforces.954I.Yet Another String Matching Problem(FFT)
\(Description\)
对于两个串\(a,b\),每次你可以选择一种字符,将它在两个串中全部变为另一种字符。
定义\(dis(a,b)\)为使得\(a,b\)相等所需的最小修改次数。
给定两个串\(S,T\),对于\(S\)中所有长为\(|T|\)的子串\(S'\),输出\(dis(S',T)\)。
\(1\leq|T|\leq|S|\leq125000\),字符集为\(a\sim f\)。
\(Solution\)
考虑\(dis(a,b)\)怎么求。用一个并查集,依次枚举\(a_i,b_i\),如果\(a_i\neq b_i\)且\(a_i,b_i\)还不在一个集合内,就将它们合并,\(dis\)++。
(也可以考虑建一张无向图,在\(a_i,b_i\)间连边。因为每个连通块最后都要变成同一个字符,所以\(dis=节点数(6)-连通块数\))
考虑枚举每一个位置\(i\in[0,|S|-|T|]\),我们需要对每个\(j\in[0,|T|-1]\),都判一下是否需要合并\(S_{i+j},T_j\),复杂度是\(O(|S||T|)\)的。但事实上我们只需要判断,这\(6\)种字符之间,是否在同一位置上出现过两种不同字符就可以了(然后尝试把它们合并)。
也就是枚举两种不同的字符\(a,b\),判一下它们在哪些位置同时出现了(\(S_i=a\)而\(T_i=b\))。
令\(f_i=[S_i=a],\ g_i=[T_i=b]\),\(F(x)=\sum_{i=0}^{|T|-1}f_{x+i}g_i\)。\(F(x)\)可以用\(FFT\)求出。
若\(F(x)\neq0\),那么\(a,b\)就在同一位置出现了,而且是在\(x\)处的子串中。枚举\(x\)时尝试合并一下\(a,b\)就可以了。
这样复杂度\(O(36n\log n+36n\alpha(n))\)+FFT的大常数。\(CF\)比较轻松过,\(BZOJ\)就算了。。
当然有很多可以优化的地方,比如减少\(f,g\)的\(FFT\)次数(1653ms->686ms)。
\(CF\)上还有两种更优的做法,没太看懂。。
//686ms 63900KB(1653ms 18800KB)
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gc() getchar()
const int N=(1<<18)+5;
const double PI=acos(-1);
int rev[N],fa[6];
char S[N],T[N];
bool neq[N][6][6];
struct Complex
{
double x,y;
Complex(double x=0,double y=0):x(x),y(y) {}
Complex operator +(const Complex &a) {return Complex(x+a.x, y+a.y);}
Complex operator -(const Complex &a) {return Complex(x-a.x, y-a.y);}
Complex operator *(const Complex &a) {return Complex(x*a.x-y*a.y, x*a.y+y*a.x);}
}f[6][N],g[6][N],F[N];
void FFT(Complex *a,int lim,int opt)
{
for(int i=1; i<lim; ++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
for(int i=2; i<=lim; i<<=1)
{
int mid=i>>1; Complex Wn(cos(PI/mid),opt*sin(PI/mid));
for(int j=0; j<lim; j+=i)
{
Complex w(1,0),t;
for(int k=j; k<j+mid; ++k,w=w*Wn)
a[k+mid]=a[k]-(t=w*a[k+mid]), a[k]=a[k]+t;
}
}
if(opt==-1) for(int i=0; i<lim; ++i) a[i].x/=lim;
}
int Find(int x)
{
return x==fa[x]?x:fa[x]=Find(fa[x]);
}
int main()
{
scanf("%s%s",S,T);
int n=strlen(S),m=strlen(T),lim=1,l=-1;
while(lim<=n+m) lim<<=1,++l;
for(int i=1; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
std::reverse(T,T+m);//!
for(int a=0; a<6; ++a)//!
{
const char aa=a+97;
for(int i=0; i<n; ++i) f[a][i]=Complex(S[i]==aa,0);
for(int i=0; i<m; ++i) g[a][i]=Complex(T[i]==aa,0);
FFT(f[a],lim,1), FFT(g[a],lim,1);
}
for(int a=0; a<6; ++a)
for(int b=0; b<6; ++b)
{
if(a==b) continue;
// for(int i=0; i<lim; ++i) f[i].x=f[i].y=g[i].x=g[i].y=0;
// for(int i=0; i<n; ++i) f[i]=Complex(S[i]==a,0);
// for(int i=0; i<m; ++i) g[i]=Complex(T[i]==b,0);
// FFT(f,lim,1), FFT(g,lim,1);
for(int i=0; i<lim; ++i) F[i]=f[a][i]*g[b][i];
FFT(F,lim,-1);
for(int i=0; i<n; ++i) neq[i][a][b]=(int)(F[m+i-1].x+0.5);
}
for(int i=0; i<=n-m; ++i)
{
for(int j=0; j<6; ++j) fa[j]=j;
int ans=0;
for(int j=0; j<6; ++j)
for(int k=0; k<6; ++k)
if(neq[i][j][k]&&Find(j)!=Find(k)) ++ans,fa[fa[j]]=fa[k];
printf("%d ",ans);
}
return 0;
}
Codeforces.954I.Yet Another String Matching Problem(FFT)的更多相关文章
- Codeforces 954I Yet Another String Matching Problem(并查集 + FFT)
题目链接 Educational Codeforces Round 40 Problem I 题意 定义两个长度相等的字符串之间的距离为: 把两个字符串中所有同一种字符变成另外一种,使得两个 ...
- 954I Yet Another String Matching Problem
传送门 分析 我们先考虑暴力如何计算 对于S的子串SS,如果它有位置i使得SS[i] != T[i]那么我们就将两个字符之间用并查集连边 最后答案很明显就是并查集中所有边的个数 于是我们可以发现对于S ...
- 【CF954I】Yet Another String Matching Problem(FFT)
[CF954I]Yet Another String Matching Problem(FFT) 题面 给定两个字符串\(S,T\) 求\(S\)所有长度为\(|T|\)的子串与\(T\)的距离 两个 ...
- Educational Codeforces Round 40 I. Yet Another String Matching Problem
http://codeforces.com/contest/954/problem/I 给你两个串s,p,求上一个串的长度为|p|的所有子串和p的差距是多少,两个串的差距就是每次把一个字符变成另一个字 ...
- CF954I Yet Another String Matching Problem 并查集、FFT
传送门 题意:给出两个由小写$a$到$f$组成的字符串$S$和$T$($|S| \geq |T|$),给出变换$c1\,c2$表示将两个字符串中所有$c1$字符变为$c2$,求$S$的每一个长度为$T ...
- CF954I Yet Another String Matching Problem(FFT+并查集)
给定两个字符串\(S,T\) 求\(S\)所有长度为\(|T|\)子串与\(T\)的距离 两个等长的串的距离定义为最少的,将某一个字符全部视作另外一个字符的次数. \(|T|<=|S|<= ...
- 2018牛客网暑假ACM多校训练赛(第三场)D Encrypted String Matching 多项式 FFT
原文链接https://www.cnblogs.com/zhouzhendong/p/NowCoder-2018-Summer-Round3-D.html 题目传送门 - 2018牛客多校赛第三场 D ...
- CF954I Yet Another String Matching Problem
传送门 每次操作可以把两个字符串中所有同一种字符变成另外一种 定义两个长度相等的字符串之间的距离为:使两个字符串相等所需要操作的次数的最小值 求 \(s\) 中每一个长度为 \(|t|\) 的连续子串 ...
- string matching(拓展KMP)
Problem Description String matching is a common type of problem in computer science. One string matc ...
随机推荐
- CF 833B
互测题T3... 首先有个dp是非常好想的: 设dp[i][j]为前j个数分成i组的最大得分,则易得:dp[i][j]=max{dp[i-1][k-1]+num[k][j]},其中,num[k][j] ...
- linux下安装pip与pip安装
在执行脚本的时候,说有库找不到 pip安装的时候说不认识pip 安装pip 使用脚本安装和升级pip wget https://bootstrap.pypa.io/get-pip.py 运行脚本pyt ...
- 第八周学习总结-C#、C++
2018年9月2日 今天是小学期开始第三天,本周前几天看了看C#和C++,用C#窗体做了个计算器,然后还用Scratch做了一个贪吃蛇的脚本. 31号小学期开始,到今天我把A类基本做完了.一开始做通讯 ...
- Linux文件系统及文件类型
Linux文件系统: 根文件系统(rootfs) root filesystem LSB, FHS: (FileSystem... /etc, /usr, /var, /root.... /bo ...
- 剑指offer之二叉树
二叉树前序,中序,后序遍历思想 前序遍历:ABDCEFGH 中序遍历:BDAFEHGC 后序遍历:DBFHGECA 科普 队列(queue)是一种常用的数据结构,可以将队列看做是一种特殊的线性表,该结 ...
- Dom,查找标签和操作标签
Dom,查找标签和操作标签 文档对象模型(Document Object Model,DOM)是一种用于HTML和XML文档的编程接口.它给文档提供了一种结构化的表示方法,可以改变文档的内容和呈现方式 ...
- Top 查看某些或者某个进程(top -p pid)
https://blog.csdn.net/zhangfn2011/article/details/7488746?utm_source=blogxgwz5
- jQuery字体缩放缩放插件zoomFontSize.js
插件描述:jQuery字体缩放缩放插件zoomFontSize.js根据父类进行百分比缩放,兼容性如下: 使用方法 body 的class属性 添加 changbody_fontSize 而且整个页面 ...
- Vuex详解笔记2
关于 state 每个vuex 应用只有一个 store 实例,所以使用起来不会太复杂,对于定位错误状态和操作会很方便. 简单用法:在vuex 的计算属性中返回vuex 的状态 最基本的使用方式,通过 ...
- [转] AES,SHA1,DES,RSA,MD5区别
AES:更快,兼容设备,安全级别高: SHA1:公钥后处理回传 DES:本地数据,安全级别低 RSA:非对称加密,有公钥和私钥 MD5:防篡改 相关: 公开密钥加密(英语:public-key cry ...