【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;
}
posted @ 2021-04-05 21:25  冰雾  阅读(112)  评论(0编辑  收藏  举报