联考20200612 T2 「雅礼集训 2018 Day11」字符串

题目传送门

分析:
集合G的成功的答案不好算,我们可以用1减去失败的概率,失败的的情况只可能是随机区间在G相邻两个元素之间
我们考虑集合删除,最暴力的就是使用Set直接删除
单次删除(O(logn))不优,这道题维护信息只考虑删除的话可以使用双向链表
但是插入就麻烦了,我们不知道当前插入的关键点在哪里,需要二分,怎么做到(O(1))
我们先把所有的字符串放进去检验,可以把Trie上的所有点的(f)求出来,并求出集合(G)
这样所有的关键点都求了出来,我们就可以保存好关键点(O(1))插入了
可以使用莫队,但是链表插入时,插入的顺序必须严格对应之前删除的顺序,否则双向链表就会出现错误
于是使用黑科技:回滚莫队,不会的童鞋可以看看这篇博客
然后直接维护就好了

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<queue>
#include<map>

#define maxn 300005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,A,B,C,L,S,Q;
struct node{
	int l,r,id;
}q[maxn];
char s[maxn];
int val[maxn],len[maxn],bl[maxn],g[maxn];
int ch[maxn][26],dpt[maxn],cur;
int p[maxn],tot,pos[maxn],v[maxn],b[maxn];
int stk[maxn],tp;
int l[maxn],r[maxn];
long long F[maxn],ans[maxn];
long long Sum,Now;
inline bool cmp(node x,node y){return bl[x.l]==bl[y.l]?x.r>y.r:x.l<y.l;}

inline void insert(int x)
{
	int now=0;
	for(int i=1;i<=len[x];i++)
	{
		int c=s[i]-'a';
		if(!ch[now][c])ch[now][c]=++cur,dpt[cur]=dpt[now]+1;
		now=ch[now][c],pos[++tot]=now,v[tot]=val[x];
	}
}
inline long long cal(long long x)
{return x*(x+1)/2;}
inline long long gcd(long long p,long long q)
{return q?gcd(q,p%q):p;}

inline bool check(long long X,long long Y)
{return X?B*X+Y*A>=C:0;}
inline void add(int i)
{
	int x=pos[i];
	if(!check(F[x],dpt[x])&&check(F[x]+v[i],dpt[x])&&!(b[g[dpt[x]]]++))
	{
		int k=g[dpt[x]],ll=l[k],rr=r[k];
		r[ll]=k,l[rr]=k,Now+=cal(rr-ll-1),Now-=cal(k-ll-1),Now-=cal(rr-k-1);
	}
	F[x]+=v[i];
}
inline void del(int i)
{
	int x=pos[i];
	if(check(F[x],dpt[x])&&!check(F[x]-v[i],dpt[x])&&!(--b[g[dpt[x]]]))
	{
		int k=g[dpt[x]],ll=l[k],rr=r[k];
		r[ll]=rr,l[rr]=ll,Now-=cal(rr-ll-1),Now+=cal(k-ll-1),Now+=cal(rr-k-1);
	}
	F[x]-=v[i];
}

int main()
{
	n=getint(),A=getint(),B=getint(),C=getint();
	for(int i=1;i<=n;i++)val[i]=getint();
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1),L=max(L,len[i]=strlen(s+1));
		insert(i),len[i]+=len[i-1];
	}
	S=sqrt(tot);
	for(int i=1;i<=tot;i++)bl[i]=(i-1)/S+1;
	for(int i=1;i<=L;i++)g[i]=getint();
	Q=getint();
	Now=Sum=cal(L);
	for(int i=1;i<=Q;i++)
		q[i].l=len[getint()-1]+1,q[i].r=len[getint()],q[i].id=i;
	sort(q+1,q+Q+1,cmp);
	for(int i=1,x=pos[i];i<=tot;i++,x=pos[i])
	{
		if(!check(F[x],dpt[x])&&check(F[x]+v[i],dpt[x])&&!(b[g[dpt[x]]]++))
			stk[++tp]=g[dpt[x]];
		F[x]+=v[i];
	}
	stk[++tp]=0,stk[++tp]=L+1;sort(stk+1,stk+tp+1);
	for(int i=1;i<=tp;i++)l[stk[i]]=stk[i-1],r[stk[i]]=stk[i+1];
	for(int i=2;i<=tp;i++)Now-=cal(stk[i]-stk[i-1]-1);
	for(int i=1,j=S,now=1,l=i,r=tot;i<=tot&&now<=Q;i+=S,j+=S)
	{
		while(now<=Q&&q[now].l>=i&&q[now].l<=j)
		{
			while(r>q[now].r)del(r--);while(l<q[now].l)del(l++);
			ans[q[now].id]=Now;while(l>i)add(--l);now++;
		}
		while(r<tot)add(++r);while(l<=j)del(l++);
	}
	for(int i=1;i<=Q;i++)
	{
		long long tmp=gcd(ans[i],Sum);
		printf("%lld/%lld
",ans[i]/tmp,Sum/tmp);
	}
}

原文地址:https://www.cnblogs.com/Darknesses/p/13110615.html