您的位置:首页 > 其它

[codeforces616F]Expensive Strings

2016-07-14 20:46 309 查看

题目大意

给出n个字符串以及一个n个元素的c数组。

定义一个字符串s的价值为:∑i=1nc[i]∗p[s][i]∗|s| 其中p[s][i]为字符串s在第i个字符串中出现的次数。

求价值最大的字符串的价值。

数据范围

n≤100000 字符串总长≤500000 ci的绝对值不超过107

分析

答案肯定是n个字符串中的某一个串的子串。

把n个字符串放进后缀自动机里,然后p[s][i]就是s在自动机上跑到一个状态后,该状态right集中r在字符串i里的个数。

加上c[i]的影响,用一个f[x][i]数组来表示状态x的right集中r在字符串i里的个数乘以c[i]。然后每个i的答案都互不影响,所以可以把全部i的答案放在一起统计。

那么变成f[x]=∑sizei=1c[pos[ri]] 其中size为x的right集合大小,pos[ri]表示ri属于哪个字符串。

我们可以先把每个字符串在后缀自动机上跑,给跑到的每个前缀的状态的f都加上c[i]。然后自下而上用每个f[i]更新f[parent[i]]。parent是形成一棵树的,所以随便搞搞。

对于一个状态x,它确定子串的最大长度为max[x],所以ans=max(f[x]∗max[x])

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=1000005,maxm=100005;

typedef long long LL;

int n,tot,last,e[maxn][26],st[maxm],v[maxm],Parent[maxn],Max[maxn],data[maxn],degree[maxn];

LL ans,f[maxn];

char c,s[maxn];

void add(char c)
{
int np=++tot,p=last,q,nq;
Max[np]=Max[p]+1;
for (;p>=0 && !e[p][c-'a'];p=Parent[p]) e[p][c-'a']=np;
if (p<0) Parent[np]=0;else
{
q=e[p][c-'a'];
if (Max[q]==Max[p]+1) Parent[np]=q;else
{
nq=++tot;
memcpy(e[nq],e[q],sizeof(e[q]));
Parent[nq]=Parent[q]; Max[nq]=Max[p]+1;
Parent[np]=Parent[q]=nq;
for (;p>=0 && e[p][c-'a']==q;p=Parent[p]) e[p][c-'a']=nq;
}
}
last=np;
}

int main()
{
scanf("%d",&n);
Parent[0]=-1;
for (int i=0;i<n;i++)
{
for (c=getchar();c<'a' || c>'z';c=getchar());
st[i]=tot;
for (;c>='a' && c<='z';c=getchar()) s[tot++]=c;
}
st
=tot; tot=0;
for (int i=0;i<n;i++)
{
scanf("%d",&v[i]);
last=0;
for (int j=st[i];j<st[i+1];j++) add(s[j]);
}
for (int i=0;i<n;i++)
{
int x=0;
for (int j=st[i];j<st[i+1];j++)
{
x=e[x][s[j]-'a'];
f[x]+=v[i];
}
}
for (int i=1;i<=tot;i++) degree[Parent[i]]++;
n=tot;
tot=0;
for (int i=1;i<=n;i++) if (!degree[i]) data[++tot]=i;
for (int i=1;i<=tot;i++)
{
int x=data[i];
ans=max(ans,f[x]*Max[x]);
if (!x) break;
f[Parent[x]]+=f[x];
degree[Parent[x]]--;
if (!degree[Parent[x]]) data[++tot]=Parent[x];
}
printf("%I64d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: