BZOJ4892: [Tjoi2017]dna
这题虽然随便用啥方法求个LCP就完事了,但是显然也可以FFT,并且FFT可以允许任意个字符不同,当然缺点是字符集必须足够小。把第二个串倒过来后,对于每种字符,把出现的位置设为1,其他设为0,就可以用卷积求出所有位置该字符的匹配个数,最后把所有字符的结果加起来即可。
很久以前我就这么做了,然而并没有卡过去,今天突然看到了这题,又卡了一波就卡过去了。首先使用“1.5次FFT”的优化,然后可以让两种字符一起匹配。具体而言,一种字符的位置设为1,另一种设为m+1,这样对于卷积后的一项s,第一种字符的匹配个数是s\bmod(m+1),第二种的匹配个数是\lfloor s/(m+1)^2\rfloor。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #include<bits/stdc++.h> using namespace std; const int N=1<<16; typedef long long ll; typedef double flo; const flo pi= acos (-1.); struct vec{ flo x,y; vec operator+( const vec&b) const { return {x+b.x,y+b.y};} vec operator-( const vec&b) const { return {x-b.x,y-b.y};} vec operator*( const vec&b) const { return {x*b.x-y*b.y,x*b.y+y*b.x};} vec operator+(flo b) const { return {x+b,y};} vec operator*(flo b) const { return {x*b,y*b};} }; vec conj( const vec&b){ return {b.x,-b.y};} vec a[N],b[N],c[N],w[N/2]; void fft(vec*a, int n){ for ( int i=0,j=0;i<n;++i){ if (i<j) swap(a[i],a[j]); int k=n>>1; while ((j^=k)<k) k>>=1; } w[0]={1}; for ( int i=1;i<n;i<<=1){ for ( int j=i-2;j>0;j-=2) w[j]=w[j>>1]; vec s={ cos (pi/i), sin (pi/i)}; for ( int j=1;j<i;j+=2) w[j]=s*w[j-1]; for ( int j=0;j<n;j+=i<<1){ vec*b=a+j,*c=b+i; for ( int k=0;k<i;++k){ vec v=w[k]*c[k]; c[k]=b[k]-v,b[k]=b[k]+v; } } } } int q,m,l,r[N*2]; char u[N*2],v[N*2]; int cal( char a, const char *f){ return a==f[0]?1:a==f[1]?m+1:0; } void sol( const char *f){ for ( int i=0;i<l<<1;++i){ (i&1?a[i>>1].y:a[i>>1].x)=cal(u[i],f); (i&1?b[i>>1].y:b[i>>1].x)=cal(v[i],f); } fft(a,l); fft(b,l); for ( int i=0;i<l;++i){ int j=l-i&l-1; c[j]=vec({0,.25})*(conj(a[j]*b[j])*4-(conj(a[j])-a[i])*(conj(b[j])-b[i])*((i<l/2?w[i]:w[i-l/2]*-1)+1)); } fft(c,l); ll t=(ll)(m+1)*(m+1); for ( int i=0;i<l<<1;++i){ ll s=(i&1?c[i>>1].x:c[i>>1].y)/l+.5; r[i]+=s%(m+1)+s/t; } } int main(){ scanf ( "%d" ,&q); while (q--){ scanf ( "%s%s" ,u,v); int n= strlen (u); m= strlen (v); if (m>n) puts ( "0" ); else if (m<=3) printf ( "%d\n" ,n-m+1); else { reverse(v,v+m); l=1<<__lg(n*2-1); fill(u+n,u+l,0); fill(v+m,v+l,0); fill(r,r+l,0); l>>=1; sol( "AT" ); sol( "CG" ); int s=0; for ( int i=m-1;i<n;++i) s+=m-r[i]<=3; printf ( "%d\n" ,s); } } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术