字符串作业(四)

这篇博客介绍了多个字符串处理问题的解决方案,包括使用后缀自动机处理最长公共子串、异或性质求解特定数字、计算字符串最短子串的频率、处理字符串周期性以及字符串匹配算法。涉及到的竞赛题目和代码AC。
摘要由CSDN通过智能技术生成

「BJOI2020」封印

给出只包含小写字母 a a a, b b b的两个字符串 s s s, t t t q q q次询问,每次询问 s [ l . . . r ] s[l...r] s[l...r] t t t的最长公共子串长度。

建出 t t t的后缀自动机后在自动机上跑 s s s串得到对于每个 s s s的前缀在 t t t中匹配的最长长度 p i p_i pi,然后对于 s [ l . . . r ] s[l...r] s[l...r],二分答案 m i d mid mid,检查是否有 max ⁡ i = l + m i d − 1 r p i ≥ m i d \max_{i=l+mid-1}^rp_i \geq mid maxi=l+mid1rpimid即可。

A C   C o d e \mathcal AC \ Code AC Code

#include<bits/stdc++.h>
#define maxn 400005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define lim 18
using namespace std;

char s[maxn],t[maxn];
int q,ls,lt;
int last , fa[maxn] , len[maxn] , tr[maxn][2] , tot;
int st[lim][maxn] , lg[maxn];
void ins(int c){
   
	int u = ++tot , p = last , q;
	len[last = u] = len[p] + 1;
	for(;p != -1 && !tr[p][c];p=fa[p]) tr[p][c] = u;
	if(p == -1) fa[u] = 0;
	else if(len[q = tr[p][c]] == len[p] + 1) fa[u] = q;
	else{
   
		int v = ++tot;
		memcpy(tr[v],tr[q],sizeof tr[q]),fa[v] = fa[q] , len[v] = len[p] + 1;
		for(;p != -1 && tr[p][c] == q;p=fa[p]) tr[p][c] = v;
		fa[q] = fa[u] = v;
	}
}

int qry(int u,int v){
   
	int t = lg[v-u+1];
	return max(st[t][u] , st[t][v-(1<<t)+1]);
}

int main(){
   
	scanf("%s%s%d",s,t,&q);
	fa[0] = -1;
	ls = strlen(s) , lt = strlen(t);
	rep(i,0,lt-1) ins(t[i] - 'a');
	int u=0,L=0;
	rep(i,0,ls-1){
   
		int c = s[i] - 'a';
 		for(;u!=-1 && tr[u][c]==0;u=fa[u]);
 		if(u == -1) u = 0 , L = 0;
 		else L = min(L+1 , len[u] + 1) ,u = tr[u][c];
 		st[0][i] = L;
	}
	rep(i,2,ls) lg[i] = lg[i >> 1] + 1;
	rep(j,1,lim-1) rep(i,0,ls-(1<<j))
		st[j][i] = max(st[j-1][i] , st[j-1][i+(1<<j-1)]);
	for(;q--;){
   
		int l,r;scanf("%d%d",&l,&r);l--,r--;
		int L = 0 , R = min(r-l+1,lt) , mid;
		for(;L<R;){
   
			mid = L+R+1 >> 1;
			if(qry(l+mid-1,r) < mid) R = mid - 1;
			else L = mid;
		}
		printf("%d\n",L);
	}
}

LOJ #6537. 毒瘤题加强版再加强版

三倍经验
具体来说就是利用异或的性质,所有数异或起来等于出现奇数次的数的异或和。
如果我们要得到单独一个数字,就 h a s h hash hash一下,具体来说我们只统计   m o d   p = i \bmod p = i modp=i的数的异或和。
那么多用几个 p p p,统计出来出现次数多的数就很有可能是单独一个数字的异或和,反之多个数字的异或和很难在多个不同的 p p p下都一起满足条件。

A C   C o d e \mathcal AC \ Code AC Code

#include<bits/stdc++.h>
#define vi vector<int>
using namespace std;

int chk(int x){
   
	for(int i=2;i*i<=x;i++) if(x % i == 0) return 0;
	return 1;
}

int n,K;
vi mod;
int a[20][20100];
map<int,int>mAp;

int main(){
   
	scanf("%d%d",&n,&K);	
	for(int i=10000;mod.size() < 20;i++) if(chk(i) && rand() % 2)
		mod.push_back(i);
	for(int i=1;i<=n;i++){
   
		int x;scanf("%d",&x);
		for(int j=0;j<mod.size();j++)
			a[j][x % mod[j]] ^= x;
	}
	for(int j=0;j<mod.size();j++) for(int i=0;i<mod[j];i++)
		if(a[j][i]) mAp[a[j][i]]++;
	vector<int>ans;
	for(auto v:mAp) if(v.second > 2) ans.push_back(v.first);
	sort(ans.begin(),ans.end());
	for(int i=0;i<ans.size();i++) printf("%d\n",ans[i]);
}

CF963D Frequency of String

给出 S S S Q Q Q次询问 S S S中最短的子串 t t t的长度使得字符串 m m m t t t中出现了 k k k次。
所有询问m互不相同

可以想到求出后缀自动机的 r i g h t right right集合 S S S O ( ∣ S ∣ ) O(|S|) O(S)回答一次询问。
然后就这样写,然后就可以过。
因为所有询问 m m m互不相同,又因为对于所有长度为 k k k的串他们的 r i g h t right righ</

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值