【JZOJ7044】悄悄话
【JZOJ7044】悄悄话
by AmanoKumiko
Description
16:15,学校,机房 “最近模拟赛的时候开团好像老是被老师抓住,什么情况?”108oahnew 询问 Wu_Mr。 “还不是你老是说一大堆废话,导致我们交流时间太长,才会这么容易被发现。”Wu_Mr 一 脸嫌弃的看着 108oahnew,同时用手去摸 108oahnew 的头。 108oahnew 觉得好像是这么回事,于是就没有反抗,任由 Wu_Mr 摸着。 “那怎么办嘛,”108oahnew 红着脸问道,“有什么办法能解决吗?” “也不是没有啦,你想想,为什么你会每次说一大堆话?”Wu_Mr 把手停了下来,开始撕烤。 “因为每句话都有用嘛。” “那为什么说的慢呢?” “因为这些话说着不连贯嘛。” “这就好了,我们给每句话一个一个权值。之后你在说话的时候尽可能保证下一句是包含上 一句的,这样说不定能快一些。” “所以要说话的时候我就是一次性只能说说出一串句子,然后下一句要包含上一句?” “是的呢,而且要权值和尽可能大呢亲。还要连续的包含,断着也不太对劲。” “但是我思路不连贯也会慢啊。是不是还得按照我一开始想说的顺序来说?” “最好这样。哦不,就这样。” “好吧,下次考试就这么试一下。” 第二天 22:00,学校,机房 “你们两个怎么又交头接耳?” “阿巴阿巴……” 22:10,校门口 “你怎么还是说的这么慢?” “我脑子里在想怎么说嘛……” “你实现个程序帮你自己一下吧。”
Input
第一行一个数 n 表示要说的话的句数。 接下来 n 行,第 i 行输入一个小写字母组成的字符串和一个整数,分别表示想说的第 i 句 话的内容和权值。
Output
输出一个整数,表示可以一次性说出去的最大的权值和。
Sample Input
4
abc 10
aa 8
abaa 7
aabc 11
Sample Output
21
Data Constraint
令 leni 为第 i 个字符串的长度。
对于 10% 的数据,保证 ∑ leni ≤ 5000。
对于另 10% 的数据,保证 ∀1 ≤ i ≤ n − 1, leni ≥ leni+1。
对于另 20% 的数据,保证数据中每个字符串完全随机。
对于 100% 的数据,\(∑ leni≤ 5 × 10^5\) , \(0 ≤ vi ≤ 10^7\)。
Solution
看到多串匹配,可想到建AC自动机
设\(f[i]\)表示以\(i\)为结尾时的最大答案
显然一个点的\(f\)可以转移到以这点为\(fail\)的点上
故建出\(fail\)树
一个点更新就会影响它在\(fail\)树上的子树内的所有点
然后随便拿个数据结构维护一下即可
Code
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define Fs(i,a) for(int i=last[a];i;i=e[i].next)
#define LL long long
#define N 500010
#define ls x<<1
#define rs (x<<1)|1
LL ans,f[N],v[N];
int n,L[N],R[N],len[N],last[N],dfn[N],size[N],cnt,tot;
struct node{int en,next;}e[N*2];
void add(int a,int b){e[++tot]=(node){b,last[a]};last[a]=tot;}
char s[N],ch[N];
struct ACM{
queue<int>q;
int son[N][26],fail[N],p,pos[N];
void insert(int x){
int u=1;
F(j,1,len[x]){
!son[u][s[j]-'a']?u=son[u][s[j]-'a']=++p:u=son[u][s[j]-'a'];
pos[L[x]+j-1]=u;
}
}
void build(){
F(i,0,25)son[0][i]=1;q.push(1);
while(!q.empty()){
int u=q.front();q.pop();
F(i,0,25){
int v=son[u][i],Fail=fail[u];
if(!v){son[u][i]=son[Fail][i];continue;}
fail[v]=son[Fail][i];q.push(v);
}
}
}
}t;
struct tree{
LL Max[N*4],tag[N*4];
void push(int x){
if(!tag[x])return;
Max[ls]=max(Max[ls],tag[x]);tag[ls]=max(tag[ls],tag[x]);
Max[rs]=max(Max[rs],tag[x]);tag[rs]=max(tag[rs],tag[x]);
tag[x]=0;
}
LL query(int x,int l,int r,int pos){
if(l==r)return Max[x];
int mid=l+r>>1;push(x);
if(pos<=mid)return query(ls,l,mid,pos);
return query(rs,mid+1,r,pos);
}
void change(int x,int l,int r,int ll,int rr,LL val){
if(r<ll||l>rr)return;
if(l>=ll&&r<=rr){tag[x]=max(tag[x],val);Max[x]=max(Max[x],val);return;}
int mid=l+r>>1;push(x);
change(ls,l,mid,ll,rr,val);change(rs,mid+1,r,ll,rr,val);
Max[x]=max(Max[ls],Max[rs]);
}
}seg;
void dfs(int x){size[x]=1;dfn[x]=++cnt;Fs(i,x)dfs(e[i].en),size[x]+=size[e[i].en];}
int main(){
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
t.p=1;
scanf("%d",&n);
F(i,1,n){
scanf("%s%lld",s+1,&v[i]);
len[i]=strlen(s+1);L[i]=R[i-1]+1;R[i]=L[i]+len[i]-1;
F(j,L[i],R[i])ch[i]=s[j-L[i]+1];
t.insert(i);
}
t.build();
F(i,2,t.p)add(t.fail[i],i);
dfs(1);
F(i,1,n){
F(j,L[i],R[i]){
int w=t.pos[j];
f[i]=max(f[i],seg.query(1,1,t.p,dfn[w])+v[i]);
}
int w=t.pos[R[i]];
seg.change(1,1,t.p,dfn[w],dfn[w]+size[w]-1,f[i]);
ans=max(f[i],ans);
}
printf("%lld",ans);
return 0;
}