联考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\n",ans[i]/tmp,Sum/tmp);
}
}