codeforces 444D DZY Loves Strings

3 篇文章 0 订阅
3 篇文章 0 订阅

似乎还没有靠谱的题解嘛。。。我来写一发。

首先我们发现,每个询问都很短,最长只有四。27^4=531441,所以显然可以把这个字符串hash一下,把出现的所有位置存下来,直接丢到vector里。由于是从头到尾扫一遍,所以vector里面的元素已经是有序的了。

然后我们发现有这样一个特点:如果询问的两个字符串出现次数都不超过根号|S|,我们可以直接利用单调性扫过去,枚举A的出现位置,每次找到离它最近的B中的位置,这个可以用A出现次数+B出现次数次计算完成,所以总的复杂度是O(根号N*Q)

其他的情况下,由于出现次数超过根号N的字符串最多只有根号N个,我们可以。。。

可以什么啊!完全不懂啊!

并不是这样做的(雾)

其实,我们把相同的询问放到map里存着,其他的直接和一开始的一样处理就好了。

复杂度我也不太会证= =反正能跑过就行了。。。

附代码

#include<bits/stdc++.h>
#define N 50100
using namespace std;
char sss[N],a[5],b[5];
vector<int> cx[531442];
int len;
inline int gethas(char *c){
	int tot=0;
	for(int i=0;i<strlen(c);i++) tot=tot*27+c[i]-'a'+1;
	return tot;
}
inline void check_min(int &a,int b){if(b<a) a=b;}
map<long long,int> s;
long long base=27*27*27*27;
int main(){
	scanf("%s",sss);len=strlen(sss);
	for(int i=0;i<len;i++){
		int has=0;
		for(int j=0;j+i<len&&j<4;j++){
			has=has*27+sss[i+j]-'a'+1;
			cx[has].push_back(i);
		}
	}
	int q;scanf("%d",&q);
	while(q--){
		scanf("%s%s",a,b);
		int hasa=gethas(a),hasb=gethas(b);
		int ll=strlen(a),rr=strlen(b);
		if(hasa>hasb) swap(hasa,hasb),swap(ll,rr);
		int l=cx[hasa].size(),r=cx[hasb].size();
		int ans=1000086;
		if(l==0||r==0) puts("-1");
		else{
			if(s[hasa*base+hasb]){
				printf("%d\n",s[hasa*base+hasb]);
				continue;
			}
			for(int i=0,now=0;i<l;i++){
				while(cx[hasb][now]<cx[hasa][i]&&now<r) now++;
				if(now!=r) ans=min(ans,(int)max(cx[hasb][now]+rr,cx[hasa][i]+ll)-cx[hasa][i]);
				if(now!=0) ans=min(ans,(int)max(cx[hasb][now-1]+rr,cx[hasa][i]+ll)-cx[hasb][now-1]);
			}
			printf("%d\n",s[hasa*base+hasb]=ans);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值