zoukankan      html  css  js  c++  java
  • Gym101821D Search Engine

    String Cheese

    小F有一个字符串 (S) 和一个初始为空的字符串 (T) ,以及一个初始为 (0) 的变量 (c) 。他会不断重复进行以下两步操作,直到 (T) 的长度超过 (S) 时结束:

    1. (T) 的开头或者结尾任意添加一个字符。

    2. (T)(S) 中作为子串出现了 (k) 次,则执行操作 (c = c + k)

    小F想知道,如果合理地进行第一步操作,操作结束时 (c) 所能达到的最大值是多少。

    对于所有数据保证 (1le |S|le 5 imes 10^5) ,且 (S) 中仅包含小写字母。

    题解

    首先我们可以限制任何时刻(T)都要是(S)的子串,然后设(dp(T))表示从串(T)开局的最大答案。任意实现一个能子串判重的算法就可以暴力转移做到(O(n^2sigma))。后面大写字母一律代表某字符串,小写字母一律
    代表某字符。

    构建出(S)的后缀自动机。可以证明如果(right(aX)=right(X))则对于任意(Y)都有(right(aXY)=right(XY)),所以对于当前串(T)如果存在(a)使得(right(T)=right(aT))则一定存在一种最优方案第一步选择在左边添加(a),而这也就是后缀自动机上节点代表的最长串。所以我们的
    转移边有两种,一种是向后加字符,可以沿着后缀自动机走;一种是向前加字符,可以沿着parent link走,每次走到一个点直接扩展到最大长度就行了,这两者都可以按拓扑序倒序算dp值,复杂度就是构建后缀自动机的复杂度。

    CO int N=1e6;
    int last=1,tot=1;
    array<int,26> ch[N];
    int fa[N],len[N],siz[N];
    
    void extend(int c){
    	int x=last,cur=last=++tot;
    	len[cur]=len[x]+1,siz[cur]=1;
    	for(;x and !ch[x][c];x=fa[x]) ch[x][c]=cur;
    	if(!x) {fa[cur]=1; return;}
    	int y=ch[x][c];
    	if(len[y]==len[x]+1) {fa[cur]=y; return;}
    	int clone=++tot;
    	ch[clone]=ch[y],fa[clone]=fa[y],len[clone]=len[x]+1;
    	fa[cur]=fa[y]=clone;
    	for(;ch[x][c]==y;x=fa[x]) ch[x][c]=clone;
    }
    
    char str[N];
    int cnt[N],ord[N];
    int64 dp[N];
    
    int main(){
    	scanf("%s",str+1);
    	int n=strlen(str+1);
    	for(int i=1;i<=n;++i) extend(str[i]-'a');
    	for(int i=1;i<=tot;++i) ++cnt[len[i]];
    	for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
    	for(int i=1;i<=tot;++i) ord[cnt[len[i]]--]=i;
    	for(int i=tot;i>=2;--i) siz[fa[ord[i]]]+=siz[ord[i]];
    	dp[1]=0;
    	for(int i=1;i<=tot;++i){
    		int x=ord[i];
    		dp[x]=max(dp[x],dp[fa[x]]+(int64)(len[x]-len[fa[x]])*siz[x]);
    		for(int c=0;c<26;++c)if(ch[x][c])
    			dp[ch[x][c]]=max(dp[ch[x][c]],dp[x]+(int64)(len[ch[x][c]]-len[x])*siz[ch[x][c]]);
    	}
    	write(dp[last],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    Using Subversion and ViewCVS on Solaris 10
    Solaris开放源代码了!
    小笨霖英语笔记本(0)
    How to start CDE/JDS with xinit command
    英译汉练习:Solaris 10进入Linux领地
    UNIX/LINUX 平台可执行文件格式分析
    小笨霖英语笔记本(2)
    小笨霖英语笔记本(3)
    小笨霖英语笔记本(1)
    魔鬼城雅丹地貌
  • 原文地址:https://www.cnblogs.com/autoint/p/13417607.html
Copyright © 2011-2022 走看看