zoukankan      html  css  js  c++  java
  • 并不对劲的bzoj4199: [Noi2015]品酒大会

    传送门->

    又称普及大会。

    这题没什么好说的……后缀自动机裸题……并不对劲的人太菜了,之前照着标程逐行比对才过了这道题,前几天刚刚把这题一遍写对……

    这题的输出和某两点相同后缀的长度有关,那么把串反过来就和相同前缀的长度有关。建出后缀自动机后,发现点u代表了right[u]个dis[fa[u]+1]~dis[u]相似的子串。此时如何统计答案就很显然了。

    想着很简单,写着嘛…其实并不长?

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register LL i=(x);i<=(y);i++)
    #define dwn(i,x,y) for(register LL i=(x);i>=(y);i--)
    #define re register
    #define maxn 600010
    #define di ord[i]
    #define LL long long
    using namespace std;
    inline LL read()
    {
        LL x=0,f=1;
        char ch=getchar();
        while(isdigit(ch)==0 && ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write_(LL x)
    {
        LL f=0;char ch[20];
        if(!x){putchar('0'),putchar(' ');return;}
        if(x<0){putchar('-');x=-x;}
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar(' ');
    }
    inline void writen(LL x)
    {
        LL f=0;char ch[20];
        if(!x){puts("0");return;}
        if(x<0){putchar('-');x=-x;}
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
    }
    LL ch[maxn][30],fa[maxn],r[maxn],dis[maxn],mn[maxn],mns[maxn],mx[maxn],mxs[maxn],lst,cnt;
    LL cc[maxn],ord[maxn],rt,n,a[maxn],ans[maxn],num[maxn],inf[4];
    char s[maxn];
    LL gx(char c){return c-'a';}
    void extend(char c)
    {
    	LL np=++cnt,p=lst;dis[np]=dis[lst]+1,lst=np;
    	for(;p&&!ch[p][gx(c)];p=fa[p])ch[p][gx(c)]=np;
    	if(p==0)fa[np]=rt;
    	else
    	{
    		LL q=ch[p][gx(c)];
    		if(dis[q]==dis[p]+1)fa[np]=q;
    		else
    		{
    			LL nq=++cnt;dis[nq]=dis[p]+1;
    			fa[nq]=fa[q],fa[q]=fa[np]=nq;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			for(;ch[p][gx(c)]==q;p=fa[p])ch[p][gx(c)]=nq;
    		}
    	}
    }
    void upd(LL x,LL y)
    {
    	r[x]+=r[y];
    	if(mn[x]<mn[y])mns[x]=min(mns[x],mn[y]);
    	else mns[x]=min(mns[y],mn[x]),mn[x]=mn[y];
    	if(mx[x]>mx[y])mxs[x]=max(mxs[x],mx[y]);
    	else mxs[x]=max(mxs[y],mx[x]),mx[x]=mx[y];
    }
    LL mul(LL x)
    {
    	LL tmx,tmn;
    	if(mx[x]!=-inf[0]&&mxs[x]!=-inf[0])tmx=mx[x]*mxs[x];
    	else tmx=-inf[0]; 
    	if(mn[x]!=inf[0]&&mns[x]!=inf[0])tmn=mn[x]*mns[x];
    	else tmn=-inf[0]; 
    	return max(tmx,tmn);
    }
    void qsort()
    {
    	memset(cc,0,sizeof(cc));
    	rep(i,1,cnt)cc[dis[i]]++; 
    	rep(i,1,n)cc[i]+=cc[i-1];
    	rep(i,1,cnt)ord[cc[dis[i]]--]=i;
    }
    int main()
    {
        n=read();
        lst=rt=++cnt;dis[0]=-1;
        scanf("%s",s+1);
        rep(i,1,n)a[i]=read();
        rep(i,1,(n>>1))swap(s[i],s[n-i+1]),swap(a[i],a[n-i+1]);
        rep(i,1,n)extend(s[i]); 
        qsort();
        memset(inf,0x7f,sizeof(inf));
        rep(i,1,cnt)mx[i]=mxs[i]=ans[i]=-inf[0],mn[i]=mns[i]=inf[0];
        LL p=rt; 
        rep(i,1,n)p=ch[p][gx(s[i])],mx[p]=mn[p]=a[i],r[p]=1;
        dwn(i,cnt,1)upd(fa[di],di); 
    	rep(i,1,cnt)
    		ans[dis[i]]=max(mul(i),ans[dis[i]]),
    		num[dis[fa[i]]+1]+=r[i]*(r[i]-1)/2,num[dis[i]+1]-=r[i]*(r[i]-1)/2;
    	dwn(i,n,1)ans[i]=max(ans[i],ans[i+1]);
    	rep(i,0,n-1)
    		num[i]+=num[i-1],write_(num[i]),
    		writen(num[i]==0?0:ans[i]);
        return 0;
    }
    /*
    10
    ponoiiipoi
    2 1 4 7 4 8 3 6 4 7
    */ 
    

      

    据说用后缀数组也能做,不过思维难度略高。

    要是觉得对后缀自动机还不够熟悉,可以试一下bzoj3238: [Ahoi2013],也是后缀自动机很好写(才怪)的题。

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iomanip>
    #include<iostream>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #define rep(i,x,y) for(register LL i=(x);i<=(y);++i)
    #define dwn(i,x,y) for(register LL i=(x);i>=(y);--i)
    #define re register
    #define maxn 1000010
    #define LL long long
    using namespace std;
    inline LL read()
    {
        LL x=0,f=1;
        char ch=getchar();
        while(isdigit(ch)==0 && ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(LL x)
    {
        LL f=0;char ch[20];
        if(!x){puts("0");return;}
        if(x<0){putchar('-');x=-x;}
        while(x)ch[++f]=x%10+'0',x/=10;
        while(f)putchar(ch[f--]);
        putchar('
    ');
    }
    LL ch[maxn][30],fa[maxn],dis[maxn],yes[maxn],lst,rt,cntnd;
    LL v[maxn],nxt[maxn],fir[maxn],siz[maxn],ans[maxn],cntrd,len;
    char s[maxn];
    void ade(LL u1,LL v1){v[++cntrd]=v1,nxt[cntrd]=fir[u1],fir[u1]=cntrd;}//u->v 
    LL gx(char c){return c-'a';}
    void extend(char c)
    {
    	LL np=++cntnd,p=lst;dis[np]=dis[p]+1,lst=np;
    	for(;p&&ch[p][gx(c)]==0;p=fa[p])ch[p][gx(c)]=np;
    	if(!p)fa[np]=rt;
    	else
    	{
    		LL q=ch[p][gx(c)];
    		if(dis[q]==dis[p]+1)fa[np]=q;
    		else
    		{
    			LL nq=++cntnd;dis[nq]=dis[p]+1;
    			fa[nq]=fa[q],fa[np]=fa[q]=nq;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			for(;ch[p][gx(c)]==q;p=fa[p])ch[p][gx(c)]=nq;
    		}
    	}
    }
    void getans(LL u)
    {
    	if(yes[u])siz[u]=1;
    	LL tmp=0;
    	for(LL k=fir[u];k!=-1;k=nxt[k])
    	{
    		getans(v[k]);
    		siz[u]+=siz[v[k]];
    	}
    	for(LL k=fir[u];k!=-1;k=nxt[k])
    	    tmp+=siz[v[k]]*(siz[u]-siz[v[k]]);
    	ans[u]=tmp*dis[u]+yes[u]*(siz[u]-1ll)*dis[u];
    }
    int main()
    {
        memset(fir,-1,sizeof(fir));
        memset(ans,0,sizeof(ans));
        lst=rt=++cntnd;dis[0]=-1;
        scanf("%s",s+1);
        len=strlen(s+1);
        rep(i,1,len)swap(s[i],s[len-i+1]);
        rep(i,1,len)extend(s[i]);
        LL p=rt;
        rep(i,1,cntnd)ade(fa[i],i);
        rep(i,1,len)p=ch[p][gx(s[i])],yes[p]=1;
        getans(rt);
        LL ansans=0; 
        rep(i,1,cntnd)ansans+=ans[i];
        write((len+1ll)*len*(len-1ll)/2ll-ansans);
        return 0;
    }
    /*
    cacao
    */ 
    

     最后祝您身体健康,再见。

  • 相关阅读:
    表单标签
    无序列表有序列表
    跳转锚点
    HTML标签01
    HTML基本结构和属性
    python爬虫学习笔记(二十三)-Scrapy框架 CrawlSpider
    python爬虫学习笔记(二十二)-Scrapy框架 案例实现
    python爬虫学习笔记(二十一)-Scrapy框架 setting
    python爬虫学习笔记(二十)-Scrapy框架 Pipeline
    python爬虫学习笔记(十九)-Scrapy 数据的保存
  • 原文地址:https://www.cnblogs.com/xzyf/p/8693944.html
Copyright © 2011-2022 走看看