ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

luogu P6229 [BalticOI 2019 Day2]项链

2021-05-02 16:34:57  阅读:204  来源: 互联网

标签:f2 now int luogu P6229 mid BalticOI mod define


题面传送门
希望早日有好的spj。
看到这道题应该可以直接秒了\(O(n^3)\):枚举第一个串中的两个端点,然后枚举第二个串的重构循环开始的地方,两边跑lcp/lcs看能否成立。
然后你发现lcp和lcs显然可以hash+倍增\(O(n^2logn)\)跑出来,关键是判断的地方。
设\(f_{i,j}\)为第一个串的\(j\)和第二个串的\(i\)同时向左跑能跑到的长度,\(g_{i,j}\)为向右。
那么我们需要判断的是对于一个区间\([j,k]\)有没有一个\(i\)满足\(f_{i,j}+g_{i+1,k}\geq k-j+1\)
移项,变成\(f_{i,j}+j-1\geq k-g_{i+1,k}\),也就是固定\(i,j\)时你需要找到最大的\(k\)满足这个式子,那么预处理后缀min倍增即可。
时间复杂度\(O(n^2logn)\)
code:

#include<cstdio>
#include<cstring>
#define N 3000
#define mod 1000000007
#define ll long long
#define I inline 
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int  n,m,k,x,y,z,lg[N+5],st[N+5],f1[N+5],f2[N+5],now,pus,ans,tot1,tot2,l,r,mid;ll f[N+5],g[N+5],ba[N+5],inv[N+5];
char a[N+5],b[N+5];
I ll mpow(ll x,int y=mod-2){ll ans=1;while(y) (y&1)&&(ans=ans*x%mod),y>>=1,x=x*x%mod;return ans;}
I ll findf(int x,int y){return (f[y]-f[x-1]+mod)*inv[x]%mod;}
I ll findg(int x,int y){return (g[y]-g[x-1]+mod)*inv[x]%mod;}
I void swap(char &x,char &y){char c=x;x=y;y=c;}
I void work(int i,int flag){
	register int j,h;
	for(j=1;j<=m;j++)g[j]=(g[j-1]+(b[j]-'a'+1)*ba[j])%mod;
	for(j=1;j<=n;j++){
		now=i-1;pus=j;l=0;r=i-1;
		while(l+1<r) mid=l+r>>1,(findg(mid,i-1)==findf(j-(i-mid)+1,j)?r:l)=mid;
		f1[j]=i-r;
		now=i;pus=j;l=i;r=n+1;
		while(l+1<r) mid=l+r>>1,(findg(i,mid)==findf(j,j+(mid-i))?l:r)=mid;
		//printf("%lld %lld\n",findg(5,6),findf(4,5));
		f2[j]=l-i+1;
	}
	for(st[n+1]=1e9,j=n;j;j--)  st[j]=min(st[j+1],j-f1[j]);
//	printf("%d\n",i);printf("%s\n",b+1);for(j=1;j<=n;j++) printf("%d %d\n",f1[j],f2[j]);printf("\n");
	for(j=1;j<=n;j++){
		now=n;
		for(h=lg[n];~h;h--) if(now>=(1<<h)&&st[now-(1<<h)+1]>f2[j]+j-1) now-=(1<<h);
		if(now-j+1>ans) ans=now-j+1,/*printf("%d %d %d %d %d %s\n",ans,i,f1[now],f2[j],flag,b+1),*/tot1=j-1,tot2=(flag!=1?(m-(i+f2[j])+1):(i-f1[now]-1));
	}
	for(j=1;j<=m/2;j++) swap(b[j],b[m-j+1]);
}
int main(){
//	freopen("necklace.in","r",stdin);freopen("necklace.out","w",stdout);
	register int i,j,h;scanf("%s%s",a+1,b+1);n=strlen(a+1);m=strlen(b+1);k=max(n,m);
	for(i=2;i<=k;i++)lg[i]=lg[i/2]+1;ba[0]=inv[0]=1;
	for(i=1;i<=k;i++) ba[i]=ba[i-1]*131%mod,inv[i]=inv[i-1]*mpow(131)%mod;
	for(i=1;i<=n;i++)f[i]=(f[i-1]+(a[i]-'a'+1)*ba[i])%mod;
	for(i=1;i<=m+1;i++)work(i,1),work(m-i+2,-1);
	printf("%d\n%d %d",ans,tot1,tot2);
}

交上去发现和\(O(n^3)\)暴力同分。/cy
然后卡下常发现两个lcp和lcs其实可以递推做到\(O(n^2)\)大大减小了常数。这个复杂度其实loj上就可以过了。
然而这个log让人很不爽。
看到后面这个二分,如果我们能保证f2[j]+j-1有序我们其实可以双指针维护。
又因为这个很小不超过\(n\)所以可以桶排之后维护即可。
时间复杂度\(O(n^2)\)小常数,LOJ评测记录可以发现很快。
code:

#include<cstdio>
#include<cstring>
#define N 3000
#define mod 1000000007
#define I inline 
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int  n,m,k,x,y,z,lg[N+5],st[N+5],f1[N+5],f2[N+5],now,pus,ans,tot1,tot2,f[N+5];
char a[N+5],b[N+5];
I void swap(char &x,char &y){char c=x;x=y;y=c;}
I void work(int i,int flag){
	register int j,l;
	for(j=n;j;j--) f1[j]=(b[i-1]==a[j])?f1[j-1]+1:0;
	for(j=n;j;j--){if(f2[j-1]>1){f2[j]=f2[j-1]-1;continue;}f2[j]=0;while(j+f2[j]<=n&&i+f2[j]<=m&&b[i+f2[j]]==a[j+f2[j]]) f2[j]++;}
	for(st[n+1]=1e9,j=n;j;j--)  st[j]=min(st[j+1],j-f1[j]);
	memset(f,0x3f,sizeof(f));for(j=1;j<=n;j++) f[f2[j]+j-1]=min(j,f[f2[j]+j-1]);l=1;
	for(j=1;j<=n;j++){
		while(st[l]<=j) l++;
		if(l-f[j]>ans) ans=l-f[j],tot1=f[j]-1,tot2=(flag!=1?(m-(i+f2[f[j]])+1):(i-f1[l-1]-1));
	}
}
int main(){
	freopen("necklace.in","r",stdin);freopen("necklace.out","w",stdout);
	register int i,j,h;scanf("%s%s",a+1,b+1);n=strlen(a+1);m=strlen(b+1);k=max(n,m);
	for(i=1;i<=m+1;i++)work(i,1);
	for(i=1;i<=m/2;i++) swap(b[i],b[m-i+1]);memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2));
	for(i=1;i<=m+1;i++)work(i,-1);
	printf("%d\n%d %d",ans,tot1,tot2);
}

标签:f2,now,int,luogu,P6229,mid,BalticOI,mod,define
来源: https://www.cnblogs.com/275307894a/p/14725886.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有