LA4671 K-neighbor substrings(FFT + 字符串Hash)
题目
Source
http://acm.hust.edu.cn/vjudge/problem/19225
Description
The Hamming distance between two strings of the same length is defined as the number of positions at which the corresponding characters are different. For example, the Hamming distance between “abbab” and “bbabb” is 3.
A string is called a K-neighbor of another string if and only if they are of the same length and the Hamming distance between them is not larger than K. In this problem, given an integer K and two strings A and B which only contain character ‘a’ and ‘b’, you are to count how many different sub-strings of A are K-neighbors of B.
Input
The input consists of multiple test cases. Each test case starts with a line containing one integer K (0 ≤ K ≤ 100, 000).
The following two lines give two non-empty strings consisting of ‘a’ and ‘b’, which are string A and string B, respectively.
The length of strings A and B will both lie between 1 and 100,000, inclusive. The last test case is followed by a line containing one ‘-1’.
Output
For each test case, print a line containing the test case number (beginning with 1) followed by the number of different sub-strings of string A which are K-neighbors of string B.
Sample Input
0
aabbab
ab
1
aabbab
ab
2
aabba
ab
-1
Sample Output
Case 1: 1
Case 2: 3
Case 3: 4
分析
题目大概说给两个由'a'和'b'组成的字符串A和B,问A有几个不同的子串满足其长度等于B且与B各个对应位置不同的字符总数不超过k。
颠倒数组转化成可以用FFT解决的卷积形式。。原来是这么个意思。
http://blog.csdn.net/pure_lady/article/details/48749635
假设len(B)=n,将B翻转,然后A与B对应位置就是A[x]与B[n-1]、A[x+1]与B[n-2]、...、A[x+n-1]与B[0],可以发现(x)+(n-1) = (x+1)+(n-2) = ... = (x+n-1)+(0),类似多项式乘法。
然后如果把'a'作为1,'b'作为0,字符串各个位置作为指数,表示出A和反转的B的两个多项式,用FFT求出乘积,即类似这种ΣA(i)B(n-i)卷积形式,最后得出这个乘积的结果中指数为x+(n-1)(0<=x<len(A)-(n-1))的系数就表示A中以x+(n-1)结尾的子串有多少个'a'与B串对应位置相同;
把'b'作为1,'a'作为0作同样处理即可同样得出A中各个子串'b'对应位置相同的个数。
感觉还是挺神奇的。。
这样不同个数不超过k就相当于相同个数大于等于len(B)-k。不过问题要求的是不同的子串,还要去掉重复的。。
可以用字符串Hash做。。字符串Hash我是乱搞的,改了几个值,改了模数,又尝试了双重hash。。WA又TLE十多次后,最后终于AC了。。
其实我不会字符串Hash,全都是乱搞的= =。。
不过后缀数组也是可以做的,本来要放弃改用后缀数组的,没想到居然AC了。。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
#define MAXN 277777
#define MOD 9999999967LL
const double PI=acos(-1.0); struct Complex{
double real,imag;
Complex(double _real,double _imag):real(_real),imag(_imag){}
Complex(){}
Complex operator+(const Complex &cp) const{
return Complex(real+cp.real,imag+cp.imag);
}
Complex operator-(const Complex &cp) const{
return Complex(real-cp.real,imag-cp.imag);
}
Complex operator*(const Complex &cp) const{
return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
}
void setValue(double _real=0,double _imag=0){
real=_real; imag=_imag;
}
}; int len;
Complex wn[MAXN],wn_anti[MAXN]; void FFT(Complex y[],int op){
for(int i=1,j=len>>1,k; i<len-1; ++i){
if(i<j) swap(y[i],y[j]);
k=len>>1;
while(j>=k){
j-=k;
k>>=1;
}
if(j<k) j+=k;
}
for(int h=2; h<=len; h<<=1){
Complex Wn=(op==1?wn[h]:wn_anti[h]);
for(int i=0; i<len; i+=h){
Complex W(1,0);
for(int j=i; j<i+(h>>1); ++j){
Complex u=y[j],t=W*y[j+(h>>1)];
y[j]=u+t;
y[j+(h>>1)]=u-t;
W=W*Wn;
}
}
}
if(op==-1){
for(int i=0; i<len; ++i) y[i].real/=len;
}
}
void Convolution(Complex A[],Complex B[],int n){
for(len=1; len<(n<<1); len<<=1);
for(int i=n; i<len; ++i){
A[i].setValue();
B[i].setValue();
}
FFT(A,1); FFT(B,1);
for(int i=0; i<len; ++i){
A[i]=A[i]*B[i];
}
FFT(A,-1);
} char s1[111111],s2[111111];
int cnt[MAXN];
Complex A[MAXN],B[MAXN]; int main(){
for(int i=0; i<277777; ++i){
wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
wn_anti[i].setValue(wn[i].real,-wn[i].imag);
}
int k,cse=0;
while(scanf("%d",&k)==1 && k!=-1){
scanf("%s%s",s1,s2);
int n1=strlen(s1),n2=strlen(s2); if(n1<n2){
printf("Case %d: 0\n",++cse);
continue;
} for(int i=0; i<n1; ++i){
if(s1[i]=='a') A[i].setValue(1);
else A[i].setValue(0);
}
for(int i=0; i<n2; ++i){
if(s2[i]=='a') B[n2-i-1].setValue(1);
else B[n2-i-1].setValue(0);
}
for(int i=n2; i<n1; ++i){
B[i].setValue(0);
}
Convolution(A,B,n1);
for(int i=0; i<len; ++i){
cnt[i]=(int)(A[i].real+0.5);
} for(int i=0; i<n1; ++i){
if(s1[i]=='b') A[i].setValue(1);
else A[i].setValue(0);
}
for(int i=0; i<n2; ++i){
if(s2[i]=='b') B[n2-i-1].setValue(1);
else B[n2-i-1].setValue(0);
}
for(int i=n2; i<n1; ++i){
B[i].setValue(0);
}
Convolution(A,B,n1);
for(int i=0; i<len; ++i){
cnt[i]+=(int)(A[i].real+0.5);
} k=n2-k; int tot=0;
long long h=0,mi=1;
set<long long> hash;
for(int i=0; i<n2-1; ++i){
h=(h*8887+s1[i]*3)%MOD;
mi*=8887; mi%=MOD;
}
for(int i=n2-1; i<n1; ++i){
h=(h*8887+s1[i]*3)%MOD;
if(hash.count(h)==0){
if(cnt[i]>=k) ++tot;
hash.insert(h);
}
h-=(s1[i-n2+1]*3*mi)%MOD;
h%=MOD; if(h<0) h+=MOD;
}
printf("Case %d: %d\n",++cse,tot);
}
return 0;
}
LA4671 K-neighbor substrings(FFT + 字符串Hash)的更多相关文章
- codeforces gym 101164 K Cutting 字符串hash
题意:给你两个字符串a,b,不区分大小写,将b分成三段,重新拼接,问是否能得到A: 思路:暴力枚举两个断点,然后check的时候需要字符串hash,O(1)复杂度N*N: 题目链接:传送门 #prag ...
- POJ 3865 - Database 字符串hash
[题意] 给一个字符串组成的矩阵,规模为n*m(n<=10000,m<=10),如果某两列中存在两行完全相同,则输出NO和两行行号和两列列号,否则输出YES [题解] 因为m很小,所以对每 ...
- 【邻接表字符串Hash】【HDU1800】Flying to the Mars
题意: 给你N个数字,带前导0,问出现最多的数字个数 思路: 读入,清楚前导0,Hash. 用邻接表字符串Hash有一下几点注意 string,不要memset,否则地址也没了,涉及到stl的东西,少 ...
- CodeForces - 727E Games on a CD 字符串Hash
题意:有n个单词,每个单词长度为k,顺时针将它们写成一个圆圈串.现在知道g个长度为k的单词,是否可以从这g个单词中选择n个形成这个圆圈串?如果有多个答案,任意输出一个. 思路 可以发现,如果枚举第一个 ...
- HDU-魔咒词典(字符串hash)
魔咒词典 TimeLimit: 8000/5000 MS (Java/Others) MemoryLimit: 32768/32768 K (Java/Others) 64-bit integer ...
- Palindrome POJ - 3974 (字符串hash+二分)
Andy the smart computer science student was attending an algorithms class when the professor asked t ...
- CodeForces7D 字符串hash + dp
https://cn.vjudge.net/problem/20907/origin 长度是 n 的字符串 s,如果它自身是回文数,且它的长度为 的前缀和后缀是 (k - )-回文数,则它被称作 k- ...
- 【题解】 Codeforces Edu44 F.Isomorphic Strings (字符串Hash)
题面戳我 Solution 我们按照每个字母出现的位置进行\(hash\),比如我们记录\(a\)的位置:我们就可以把位置表示为\(0101000111\)这种形式,然后进行字符串\(hash\) 每 ...
- CH 1402 - 后缀数组 - [字符串hash]
题目链接:传送门 描述 后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围. 在本题中,我们希望使用快排.Hash与二分实现一个简单的 $O(n \log ...
随机推荐
- [Android Pro] APK
svn updatesvn status ls -alsvn log --limit 8 > RELEASE_NOTE.txt cat RELEASE_NOTE.txt chmod a+x gr ...
- jpg Test
- 5.1 stack,queue以及priority_queue
*:stack 使用要包含头文件stack,栈是一种先进后出的元素序列,删除和访问只能对栈顶的元素(最后一个添加的元素)进行,并且添加元素只能添加到栈顶.栈内的元素不能访问,要想访问先要删除其上方的所 ...
- hdu 2159 FATE
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路:二维完全背包,状态转移方程为: f[j][l]=max(f[j][l],f[j-b[i]] ...
- JAVA数据库基本操作 (转)
JAVA数据库基本操作指南 Java数据库操作基本流程:取得数据库连接 - 执行sql语句 - 处理执行结果 - 释放数据库连接. 一.取得数据库连接 1.用DriverManager取数据库连接 ...
- Mac OS
defaults write com.apple.finder AppleShowAllFiles -bool true 此命令显示隐藏文件defaults write com.apple.finde ...
- 【转载】Pyqt 添加右键菜单方法
转载地址: http://www.cnblogs.com/yogalau/p/3954042.html?utm_source=tuicool QListWidget 是继承 QWidget 的, 所以 ...
- Validform 学习笔记---代码练习
上一节主要梳理了validform的基础知识,针对这些基础知识,编写代码的时候,也整理的部分知识,先记录以便后期温习. 验证部分的css @charset "utf-8"; /* ...
- 【Java EE 学习 21 上】【其它类型的监听器】【使用HttpSessionActivationListener监听session的活化和钝化】
一.ServletContextListener Method Summary void contextDestroyed(ServletContextEvent sce) R ...
- 【JAVA与XML、dtd约束、Schema约束】
一.XML. (1)XML:Extensible Markup Language (2)XML是一种标记语言. (3)XML的设计宗旨是传输数据,而不是显示数据. (4)XML标签没有被预定义,即使用 ...