20200706 字符串专题

CF653F Paper task

求给出的括号序列本质不同的合法括号子串个数, n ≤ 5 ∗ 1 0 5 n\le5*10^5 n5105

对每种前缀和分开统计的做法很好想。二分,区间最小值满足条件(单调栈),去重就后缀数组调整二分范围。详见 blog

后缀自动机也差不多,对每个节点找任意一个endpos,同样限制出一个范围。详见 blog2

Code

CF587F Duff is Mad

在这里插入图片描述
统计多串在某串中的出现次数,容易想到AC自动机。

s l . . . r s_{l...r} sl...r s k s_k sk 中的出现次数相当于是在 f a i l fail fail 树上对 s l . . . r s_{l...r} sl...r 对应结束节点的子树权值 +1 后 s k s_k sk 的所有节点的权值和。

差分之后,相当于求一个前缀与 s k s_k sk 的答案。
对于 s k ≤ T s_k\le T skT,可以暴力遍历 s k s_k sk 的所有节点,离线扫描 s l . . . r s_{l...r} sl...r 子树加,单点查。
对于 s k > T s_k> T sk>T,总的串个数不超过 m T \frac {m}T Tm,可以 O ( m ) O(m) O(m) 处理所有与之有关的询问:预处理 f a i l fail fail 树上每个点的子树中有多少 s k s_k sk 的节点,然后离线扫描 s l . . . r s_{l...r} sl...r 加入和。

详细的复杂度分析见 xht37’s blog

Code

CF914F Substrings in a String

在这里插入图片描述
∑ ∣ y ∣ ≤ 1 0 5 \sum |y|\le10^5 y105

分块,大小为 S S S,每个块建后缀自动机,有修改就重构对应块。 O ( n S ) O(nS) O(nS)
查询 y , [ l , r ] y,[l,r] y,[l,r],整块块内就在自动机上走,答案为endpos的个数。跨越块或者散块暴力KMP匹配。 O ( ∣ y ∣ ∗ ( n S + S ) ) O(|y|*(\frac nS+S)) O(y(Sn+S))

可以 bitset 暴力匹配,存每个位置匹配到第 i i i 位是否仍然合法,然后继续加入 i + 1 i+1 i+1 位。最后差分一下。

Code:

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m;
char s[maxn],t[maxn];
bitset<maxn>a[26],ans;
int main()
{
	scanf("%s",s+1),n=strlen(s+1);
	for(int i=1;i<=n;i++) a[s[i]-='a'][i]=1;
	scanf("%d",&m);
	for(int op,x,y,c;m--;){
		scanf("%d%d",&op,&x);
		if(op==1){
			getchar(),c=getchar()-'a';
			a[s[x]][x]=0,a[s[x]=c][x]=1;
		}
		else{
			scanf("%d%s",&y,t); int len=strlen(t);
			ans.set();
			for(int i=0;i<len;i++) ans&=a[t[i]-'a']>>i;
			printf("%d\n",(y-x+1>=len)?(ans>>x).count()-(ans>>(y-len+2)).count():0);
		}
	}
}

CF741E Arpa’s abnormal DNA and Mehrdad’s deep interest

在这里插入图片描述
洛谷题解区的 Durant_Lee 的题解写的很清晰了。

比较两个位置的字典序分成五部分(比较三段),后缀数组LCP比较。(略麻烦)
然后就可以 sort 给所有位置排序求出排名,转化为求询问区间里的排名最小值。

对于 k > S k>S k>S,可以枚举每一块,然后求在区间 [ l , r ] [l,r] [l,r] [ t k + x , t k + y ] [tk+x,tk+y] [tk+x,tk+y] 的最小值,一个全局RMQ即可。 O ( n log ⁡ n + q ∗ n S ) O(n\log n+q*\frac nS) O(nlogn+qSn)
对于 k ≤ S k\le S kS,离线询问,对每种 k k k 分开做,然后枚举余数 t ∈ [ 0 , k ) t\in[0,k) t[0,k),对所有 i ≡ t ( m o d k ) i \equiv t\pmod k it(modk) 建立RMQ, 对于 t ∈ [ x , y ] t\in[x,y] t[x,y] 的询问求 [ l , r ] [l,r] [l,r] 的最小值即可。 O ( n log ⁡ n ∗ S + q S ) O(n\log n*S+qS) O(nlognS+qS)

Code:

#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
const int S = 150;
int n,m,lg[maxn];
namespace SA{
	int ary[4][maxn],b[maxn],st[18][maxn];
	int *sa=ary[0],*rk=ary[1],*nsa=ary[2],*nrk=ary[3];
	void build(int n,char *a){
		for(int i=1;i<=n;i++) b[a[i]]++;
		for(int i=1;i<=255;i++) b[i]+=b[i-1];
		for(int i=1;i<=n;i++) sa[b[a[i]]--]=i;
		for(int i=1;i<=n;i++) rk[sa[i]]=rk[sa[i-1]]+(a[sa[i-1]]!=a[sa[i]]);
		for(int k=1;rk[sa[n]]<n;k<<=1){
			for(int i=1;i<=n;i++) b[rk[sa[i]]]=i;
			for(int i=n;i>=1;i--) if(sa[i]-k>0) nsa[b[rk[sa[i]-k]]--]=sa[i]-k;
			for(int i=n-k+1;i<=n;i++) nsa[b[rk[i]]--]=i;
			for(int i=1;i<=n;i++) nrk[nsa[i]]=nrk[nsa[i-1]]+(rk[nsa[i-1]]!=rk[nsa[i]]||rk[nsa[i-1]+k]!=rk[nsa[i]+k]);
			swap(sa,nsa),swap(rk,nrk);
		}
		for(int i=1,j,k=0;i<=n;st[0][rk[i]]=k,i++)
			for(k&&(k--),j=sa[rk[i]-1];a[i+k]==a[j+k];k++);
		for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
		for(int j=1;j<=lg[n];j++)
			for(int i=1,l=1<<j;i+l-1<=n;i++)
				st[j][i]=min(st[j-1][i],st[j-1][i+(l>>1)]);
	}
	int LCP(int x,int y){
		if(x==y) return maxn;
		if((x=rk[x])>(y=rk[y])) swap(x,y); x++;
		int k=lg[y-x+1];
		return min(st[k][x],st[k][y-(1<<k)+1]);
	}
	int cmp(int x,int y,int l){return LCP(x,y)>=l?0:rk[x]<rk[y]?-1:1;}
	bool cmp2(int x,int y){//equal return 1.
		int f=x>y,t; if(f) swap(x,y);
		if(x+m<=y){
			if(t=cmp(n+1,x+1,m)) return (t<0)^f;
			if(t=cmp(x+1,x+m+1,y-(x+m))) return (t<0)^f;
			if(t=cmp(y+1-m,n+1,m)) return (t<0)^f;
		}
		else{
			if(t=cmp(n+1,x+1,y-x)) return (t<0)^f;
			if(t=cmp(n+1+y-x,n+1,x+m-y)) return (t<0)^f;
			if(t=cmp(x+1,n+1+x+m-y,y-x)) return (t<0)^f;
		}
		return 1^f;
	}
}
int Q,RK[maxn],PS[maxn],ans[maxn],mn[18][maxn];
char s1[maxn],s2[maxn];
struct node{
	int l,r,k,x,y,id;
	void init(int i){id=i,scanf("%d%d%d%d%d",&l,&r,&k,&x,&y);}
	bool operator < (const node &p)const{return k<p.k;}
}q[maxn];
int RMQ(int x,int y){
	if(x>y) return maxn;
	int k=lg[y-x+1];
	return min(mn[k][x],mn[k][y-(1<<k)+1]);
}
void Pre(int N){
	for(int j=1;j<=lg[N+1];j++) for(int i=0,l=1<<j;i+l-1<=N;i++) mn[j][i]=min(mn[j-1][i],mn[j-1][i+(l>>1)]);
}
int main()
{
	scanf("%s%s%d",s1+1,s2+1,&Q),n=strlen(s1+1),m=strlen(s2+1);
	for(int i=1;i<=m;i++) s1[n+i]=s2[i];
	SA::build(n+m,s1);
	for(int i=0;i<=n;i++) PS[i]=i;
	sort(PS,PS+n+1,SA::cmp2);
	for(int i=0;i<=n;i++) RK[PS[i]]=i;
	for(int i=1;i<=Q;i++) q[i].init(i),ans[i]=maxn;
	
	for(int i=0;i<=n;i++) mn[0][i]=RK[i]; Pre(n);
	for(int i=1;i<=Q;i++) if(q[i].k>S)
		for(int j=0,k=q[i].k;j*k<=n;j++)
			ans[i]=min(ans[i],RMQ(max(j*k+q[i].x,q[i].l),min(j*k+q[i].y,q[i].r)));
	
	sort(q+1,q+1+Q);
	for(int k=1,s=1,t;k<=S&&k<=n&&s<=Q;k++) if(q[s].k==k){
		for(t=s;t<Q&&q[t+1].k==k;t++);
		for(int r=0;r<k;r++){
			int M = n/k-(n%k<r);
			for(int i=0;i<=M;i++) mn[0][i]=RK[i*k+r]; Pre(M);
			for(int i=s;i<=t;i++) if(q[i].x<=r&&r<=q[i].y)
				ans[q[i].id]=min(ans[q[i].id],RMQ(q[i].l/k+(q[i].l%k>r),q[i].r/k-(q[i].r%k<r)));
		}
		s=t+1;
	}
	
	for(int i=1;i<=Q;i++) printf("%d%c",ans[i]<maxn?PS[ans[i]]:-1,i==Q?10:32);
}

CF862F Mahmoud and Ehab and the final stage

在这里插入图片描述

题解

区间LCP是相邻两两LCP的最小值。

对 LCP <= K 的每种LCP开一棵线段树,如果某个位置>=LCP就为1,否则为0,查询答案就是 (区间最大子段和+1) * LCP。 O ( ( n + q ) K log ⁡ n ) O((n+q)K\log n) O((n+q)Klogn)
对 LCP > K,串的个数不超过 总长/K,把这些串拿出来建笛卡尔树,dfs求答案。可以用 vector 存这些位置,修改的时候暴力插入。 O ( q ∗ L K ) O(q*\frac LK) O(qKL)

K K K n log ⁡ n \sqrt {\frac n{\log n}} lognn 时复杂度 O ( n n log ⁡ n ) O(n\sqrt {n\log n}) O(nnlogn ),实际 K K K 取大一点。

[CTSC2010]珠宝商

在这里插入图片描述
暴力的做法是从一个树上节点开始走,在S的后缀自动机中匹配,统计endpos大小的和。

涉及路径问题,通常的想法是点分治。
统计经过点分中心 x x x 的路径有多少在 S S S 中。
在这里插入图片描述
暴力算法 B B B 中, T [ y . . . x ] T[y...x] T[y...x] S [ 1... i ] S[1...i] S[1...i] 的条件是 T [ y . . . x ] T[y...x] T[y...x] S S S 的后缀自动机中能够匹配,且 endpos 集合包含 i i i。注意这里是在 T T T 的前面添加一个点,在后缀自动机上不是走转移边,而是走 p a r e n t parent parent 树的转移边:(下面这张图截自洛谷题解区 WAPER420 的题解
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值