Codeforces gym 100269 C

博客详细介绍了如何解决Codeforces Gym 100269 C问题,通过枚举所有可能的子串A并利用后缀的最长公共前后缀(LCP)来判断是否存在合法解决方案。文章指出,通过预处理LCP数组,可以在A出现的次数复杂度内检查每个子串,并且由于所有子串的计数之和是线性平方级别的,因此总时间复杂度为O(len^2)。
摘要由CSDN通过智能技术生成

考虑直接枚举所有不同的串 A A A(显然是初始串的子串)。
若我们预处理出任意两个后缀的LCP,对于一个固定的串 A A A,我们容易在 O ( c o u n t ( A ) ) \mathcal O(count(A)) O(count(A)) A A A在初始串中的出现次数)的时间复杂度内判定是否有合法方案。注意到 ∑ A c o u n t ( A ) = O ( l e n 2 ) \sum_{A}count(A)=\mathcal O(len^2) Acount(A)=O(len2),于是我们暴力枚举即可。
时间复杂度为 O ( l e n 2 ) \mathcal O(len^2) O(len2)

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f

using namespace std;

char s1[2005],s2[2005];

int lcp1[2005][2005],lcp2[2005][2005],lcp3[2005][2005];
int nxt[2005][2005];
bool fir[2005][2005];

int pos[2005];

int main() {
  freopen("curiosity.in","r",stdin);
  freopen("curiosity.out","w",stdout);
  cin.getline(s1+1,10000);
  cin.getline(s2+1,10000);
  int n=strlen(s1+1),m=strlen(s2+1);
  for(int i=n;i>0;i--)
    for(int j=n;j>=i;j--) lcp1[i][j]=((s1[i]==s1[j])?lcp1[i+1][j+1]+1:0);
  for(int i=m;i>0;i--)
    for(int j=m;j>=i;j--) lcp2[i][j]=((s2[i]==s2[j])?lcp2[i+1][j+1]+1:0);
  for(int i=n;i>0;i--)
    for(int j=m;j>0;j--) lcp3[i][j]=((s1[i]==s2[j])?lcp3[i+1][j+1]+1:0);
  for(int i=1;i<=n;i++) {
  	int k=0;
  	for(int j=i-1;j>0;j--)
  	  while (k<lcp1[j][i]) nxt[j][++k]=i;
  	while (k<=n-i) fir[i][++k]=1;
  }
  int ans1=inf,ans2=inf,id=0;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n-i+1;j++)
      if (fir[i][j]) {
      	int sz=0;
      	for(int k=i;k;k=nxt[k][j])
      	  if (!sz||k>=pos[sz]+j) pos[++sz]=k;
      	pos[sz+1]=n+1;
      	if (n-sz*j>m||(m-(n-sz*j))%sz!=0) continue;
      	int d=(m-(n-sz*j))/sz;
      	if (pos[1]>1&&lcp3[1][1]<pos[1]-1) continue;
      	bool ok=1;
      	int r=pos[1];
      	for(int k=1;k<=sz;k++) {
      		if (lcp2[pos[1]][r]<d) {
      			ok=0;
      			break;
			  }
			r+=d;
			if (lcp3[pos[k]+j][r]<pos[k+1]-(pos[k]+j)) {
				ok=0;
				break;
			}
			r+=pos[k+1]-(pos[k]+j);
		  }
		if (ok&&j<ans1) {
			ans1=j;
			ans2=d;
			id=i;
		}
	  }
  printf("s/");
  for(int i=0;i<ans1;i++) putchar(s1[id+i]);
  printf("/");
  for(int i=0;i<ans2;i++) putchar(s2[id+i]);
  printf("/g\n");
  return 0;
}
/*
abababa
cbc
*/

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值