zoukankan      html  css  js  c++  java
  • luoguP2178 [NOI2015]品酒大会(后缀自动机)

    题意

    承接上篇题解

    考虑两个后缀的(lcp)是什么,是将串反着插入后缀自动机后两个前缀(终止节点)的(lca)!!!于是可以在parent tree上DP了。

    比后缀数组又简单又好写跑的还快。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=3*1e5+10;
    int n,last,tot,cnt;
    int head[maxn<<1],size[maxn<<1];
    ll inf;
    ll a[maxn],val[maxn<<1],maxx[maxn<<1],minn[maxn<<1],ans1[maxn],ans2[maxn];
    char s[maxn];
    struct edge{int to,nxt;}e[maxn<<1];
    struct SAM
    {
    	int fa,len;
    	int ch[30];
    }sam[maxn<<1];
    inline ll read()
    {
    	char c=getchar();ll res=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    	return res*f;
    }
    inline void add(int u,int v){e[++cnt].nxt=head[u];head[u]=cnt;e[cnt].to=v;}
    inline void sam_init(){sam[0].fa=-1;sam[0].len=0;last=0;}
    inline void sam_add(int c,int id)
    {
    	int now=++tot;sam[now].len=sam[last].len+1;size[now]=1;val[now]=a[id];
    	int p=last;last=now;
    	while(~p&&!sam[p].ch[c])sam[p].ch[c]=now,p=sam[p].fa;
    	if(p==-1){sam[now].fa=0;return;}
    	int q=sam[p].ch[c];
    	if(sam[q].len==sam[p].len+1)sam[now].fa=q;
    	else
    	{
    		int nowq=++tot;
    		sam[nowq].len=sam[p].len+1;
    		memcpy(sam[nowq].ch,sam[q].ch,sizeof(sam[q].ch));
    		sam[nowq].fa=sam[q].fa,sam[q].fa=sam[now].fa=nowq;
    		while(~p&&sam[p].ch[c]==q)sam[p].ch[c]=nowq,p=sam[p].fa;
    	}
    }
    void dfs(int x)
    {
    	maxx[x]=-inf,minn[x]=inf;
    	if(size[x])maxx[x]=minn[x]=val[x];
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		dfs(y);
    		if(minn[x]!=inf&&minn[y]!=inf&&maxx[x]!=-inf&&maxx[x]!=-inf)
    			ans2[sam[x].len]=max(ans2[sam[x].len],max(maxx[x]*maxx[y],minn[x]*minn[y]));
    		maxx[x]=max(maxx[x],maxx[y]),minn[x]=min(minn[x],minn[y]);
    		ans1[sam[x].len]+=1ll*size[x]*size[y];
    		size[x]+=size[y];
    	}
    }
    int main()
    {
    	n=read();
    	scanf("%s",s+1);
    	for(int i=1;i<=n;i++)a[i]=read();
    	sam_init();
    	for(int i=n;i;i--)sam_add(s[i]-'a',i);
    	for(int i=1;i<=tot;i++)add(sam[i].fa,i);
    	memset(ans2,-0x3f,sizeof(ans2));inf=-ans2[0];
    	dfs(0);
    	for(int i=n-1;~i;i--)ans1[i]+=ans1[i+1],ans2[i]=max(ans2[i],ans2[i+1]);
    	for(int i=0;i<n;i++)
    		if(ans1[i])printf("%lld %lld
    ",ans1[i],ans2[i]);
    		else puts("0 0");
    	return 0;
    }
    
  • 相关阅读:
    python课堂练习
    Python爬虫学习笔记(九)——Selenium的使用
    Python爬虫学习笔记(八)——智高考数据爬取
    Python爬虫学习笔记(七)——Ajax
    Python爬虫学习笔记(六)——BeautifulSoup和pyquery的使用
    Python爬虫学习笔记(五)——XPath的使用
    Python爬虫学习笔记(四)——猫眼电影Top100
    Python爬虫学习笔记(三)——正则表达式
    Python爬虫学习笔记(二)——requests库的使用
    Python爬虫学习笔记(一)——urllib库的使用
  • 原文地址:https://www.cnblogs.com/nofind/p/12054348.html
Copyright © 2011-2022 走看看