200209-省选模拟测试2

200209-省选模拟测试2

T1 串

题目描述

题目描述

题解

AC自动机。
首先对所有串,建立出AC自动机。如果不考虑重复的话显然就有 c n t 2 cnt^2 cnt2个。( c n t cnt cnt表示AC自动机中节点个数),于是考虑去重。
如果产生重复的话,显然是下图情况:
题目描述

也就是对于同一个串划分方式不同,黑色处表示划分点。
很显然,红串是蓝串的后缀,而中间圈出来的串为黄串的后缀。于是考虑枚举每一个fail指针不指向根节点的节点(即有后缀的节点),找出这两个串不同的地方(即图中圈出来的串),那么重复数就是以该串为后缀的前缀总数。

代码实现

#include<bits/stdc++.h>
#define int long long
#define M 300009 
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
int f[M],dep[M],tr[M][26],fail[M],cnt,n,sum[M];
char s[M];
void build(){
	int u=0,len=strlen(s+1);
	for(int i=1;i<=len;i++){
		int c=s[i]-'a';
		if(!tr[u][c]) tr[u][c]=++cnt;
		f[tr[u][c]]=u,dep[tr[u][c]]=dep[u]+1,u=tr[u][c];
	}
}
void getfail(){
	queue<int>q;
	for(int i=0;i<26;i++)
		if(tr[0][i]) q.push(tr[0][i]);
	while(q.size()){
		int u=q.front();q.pop();
		for(int i=0;i<26;i++){
			if(!tr[u][i]) tr[u][i]=tr[fail[u]][i];
			else{
				int x=tr[u][i],y=fail[u];q.push(x);
				while(y&&!tr[y][i]) y=fail[y];
				fail[x]=tr[y][i];
				if(fail[x]) for(int j=fail[x];j;j=fail[j]) sum[j]++;
			}
		}
	}
}
int solve(){
	int ans=0;
	for(int i=1;i<=cnt;i++)
		if(fail[i]){
			int x=i,y=fail[x];
			for(int j=1;j<=dep[y];j++) x=f[x];
			ans+=sum[x]; 
		}return ans;
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		build();
	}getfail();
	printf("%lld\n",cnt*cnt-solve());
	return 0;
}

T2 两个串

题目描述

题目描述

题解

FFT完成单模式串匹配(含通配符)
P4173-残缺的字符串

代码实现

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define M 1000009
using namespace std;
const double eps=1e-1;
const double pi=acos(-1.0);
int a[M],b[M],n,m,lim=1,l,r[M],cnt,ans[M];
char s[M],t[M];
struct complex{
	double x,y;
	complex(double a=0,double b=0){x=a,y=b;}
	friend inline complex operator+(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
	friend inline complex operator-(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
	friend inline complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
}c[M],d[M],e[M];
void FFT(complex *A,int type){
	for(int i=0;i<lim;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(int mid=1;mid<lim;mid<<=1){
		complex W(cos(pi/mid),type*sin(pi/mid));
		for(int R=mid<<1,j=0;j<lim;j+=R){
			complex w(1,0);
			for(int k=0;k<mid;k++,w=w*W){
				complex x=A[j+k],y=w*A[j+k+mid];
				A[j+k]=x+y;
				A[j+mid+k]=x-y;
			}
		}
	}
}
int main(){
	scanf("%s",s);
	scanf("%s",t);
	n=strlen(s),m=strlen(t);
	reverse(t,t+m);
	while(lim<n+m) lim<<=1,l++;
	for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	for(int i=0;i<n;i++) a[i]=s[i]-'a'+1;
	for(int i=0;i<m;i++){
		if(t[i]=='?') b[i]=0;
		else b[i]=t[i]-'a'+1;
	}
	for(int i=0;i<lim;i++) c[i].x=b[i]*b[i]*b[i];
	for(int i=0;i<lim;i++) d[i].x=1;
	FFT(c,1),FFT(d,1);
	for(int i=0;i<lim;i++) e[i]=c[i]*d[i];
	for(int i=0;i<lim;i++) c[i].x=2*a[i],c[i].y=0;
	for(int i=0;i<lim;i++) d[i].x=b[i]*b[i],d[i].y=0;
	FFT(c,1),FFT(d,1);
	for(int i=0;i<lim;i++) e[i]=e[i]-(c[i]*d[i]);
	for(int i=0;i<lim;i++) c[i].x=a[i]*a[i],c[i].y=0;
	for(int i=0;i<lim;i++) d[i].x=b[i],d[i].y=0;
	FFT(c,1),FFT(d,1);
	for(int i=0;i<lim;i++) e[i]=e[i]+(c[i]*d[i]);
	FFT(e,-1);
	for(int i=m-1;i<n;i++)
		if(fabs(e[i].x/lim)<eps) ans[++cnt]=i-m+1;
	printf("%d\n",cnt);
	for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
	return 0;
}

T3 K个串

题目描述

题目描述

题解

主席树区间修改

代码实现

#include<bits/stdc++.h>
#define M 100009
using namespace std;
int a[M],nxt[M],b[M],n,m,rt[M*7],idx[M],p[M],cnt;
long long sum[M];
const long long inf=1e17;
bool vis[M];
struct tree{
	int l,r,pos;
	long long maxn,add;
}tr[M*160];
struct data{
	long long rt,pos,val;
	data(long long _rt,long long _pos,long long _val){rt=_rt; pos=_pos; val=_val;}
    friend bool operator < (data x,data y){return x.val<y.val;}
};
priority_queue<data>q;
void pushup(int k){
	tr[k].maxn=max(tr[tr[k].l].maxn,tr[tr[k].r].maxn);
	if(tr[tr[k].l].maxn>tr[tr[k].r].maxn) tr[k].pos=tr[tr[k].l].pos;
	else tr[k].pos=tr[tr[k].r].pos;
}
void build(int k,int l,int r){
	tr[k].l=++cnt,tr[k].r=++cnt;
	if(l==r){
		tr[k].maxn=sum[l];
		tr[k].pos=l;
		return;
	}int mid=(l+r)>>1;
	build(tr[k].l,l,mid);
	build(tr[k].r,mid+1,r);
	pushup(k);
}
void add(int &k,long long val){
	int x=++cnt;
	tr[x]=tr[k];
	tr[x].add+=val;
	tr[x].maxn+=val;
	k=x;
}
void pushdown(int k){
	if(tr[k].add){
		add(tr[k].l,tr[k].add);
		add(tr[k].r,tr[k].add);
		tr[k].add=0;
	}
}
void update(int x,int &y,int l,int r,int ql,int qr,long long val){
	pushdown(x);
	y=++cnt;
	tr[y]=tr[x];
	if(l>=ql&&r<=qr) return add(y,val);
	int mid=(l+r)>>1;
	if(ql<=mid) update(tr[x].l,tr[y].l,l,mid,ql,qr,val);
	if(qr>mid) update(tr[x].r,tr[y].r,mid+1,r,ql,qr,val);
	pushup(y);
}
void debug(int k,int l,int r){
	printf("%d %d %lld %d\n",l,r,tr[k].maxn,tr[k].pos);
	if(l==r) return;
	int mid=(l+r)>>1;
	debug(tr[k].l,l,mid);
	debug(tr[k].r,mid+1,r);
}
data query(int k){
	return data(k,tr[k].pos,tr[k].maxn);
}
signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}sort(b+1,b+n+1);
	int len=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++){
		int val=lower_bound(b+1,b+len+1,a[i])-b;
		idx[val]=a[i];
		a[i]=val;
	}
	for(int i=1;i<=n;i++){
		nxt[p[a[i]]]=i;
		p[a[i]]=i;
		if(!vis[a[i]]) sum[i]=sum[i-1]+idx[a[i]];
		else sum[i]=sum[i-1];
		vis[a[i]]=1;
	}rt[1]=++cnt;
	build(rt[1],1,n);
	q.push(query(1));
	for(int i=2;i<=n;i++){
		if(!nxt[i-1]) update(rt[i-1],rt[i],1,n,i,n,-idx[a[i-1]]);
		else if(nxt[i-1]!=i)update(rt[i-1],rt[i],1,n,i,nxt[i-1]-1,-idx[a[i-1]]);
		else update(rt[i-1],rt[i],1,n,i,n,0);
		update(rt[i],rt[n+1],1,n,i-1,i-1,-inf);
		rt[i]=rt[n+1],rt[n+1]=0;
		q.push(query(rt[i]));
	}
	while(m>1){
		int w;
		data v=q.top();q.pop();
		update(v.rt,w,1,n,v.pos,v.pos,-inf);
		q.push(query(w));
		m--;
	}printf("%lld\n",q.top().val);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值