BZOJ 4199 品酒大会

以前一直听说什么后缀数组height合并之类的

表示我这种后缀数组都敲不熟的蒟蒻怎么会写

但是做了做觉得还是很简单的嘛

这个题是有两问的,第一问是求LCP>=R的后缀对有多少个

这个就是AHOI2013 差异 稍微变个形啦

直接逆序建后缀自动机,在parent树上做一个很简单的树P就可以了

因为对于现在parent树而言,任意两点的LCP等于两点在树上的LCA的len

到这里,其实我们已经可以拿到70分了

一部分数据暴力,一部分数据LCP<10也可以暴力,还有一部分数据ai相等,等价于只用求第一问

之后我们考虑第二问,对于当前的parent树而言,等价于求parent树上两个叶节点乘积的最大值

又因为考虑到ai可能是负数,所以我们只需要记录最大值,次大值,最小值,次小值就可以了

这也是一个非常简单的树P

UPD:题目可以去UOJ去看

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=600010;
const LL oo=1LL<<62;
int n,cnt,la;
int a[maxn];
char s[maxn];
struct Node{
    int next[26];
    int len,link;
}st[maxn];
int t[maxn],b[maxn];
LL ans1[maxn],ans2[maxn];
LL mx[maxn],cmx[maxn];
LL mn[maxn],cmn[maxn];
LL sum[maxn];

void read(int &num){
    num=0;int f=1;char ch=getchar();
    while(ch<‘!‘)ch=getchar();
    if(ch==‘-‘)f=-1,ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘)num=num*10+ch-‘0‘,ch=getchar();
    num*=f;
}
void init(){
    cnt=la=0;
    st[0].link=-1;
}
void add(int c){
    int cur=++cnt;
    st[cur].len=st[la].len+1;
    int p;
    for(p=la;p!=-1&&st[p].next[c]==0;p=st[p].link)st[p].next[c]=cur;
    if(p==-1)st[cur].link=0;
    else{
        int q=st[p].next[c];
        if(st[q].len==st[p].len+1)st[cur].link=q;
        else{
            int clone=++cnt;
            st[clone]=st[q];
            st[clone].len=st[p].len+1;
            for(;p!=-1&&st[p].next[c]==q;p=st[p].link)st[p].next[c]=clone;
            st[cur].link=st[q].link=clone;
        }
    }la=cur;
}

int main(){
    read(n);scanf("%s",s+1);init();
    for(int i=1;i<=n;++i)read(a[i]);
    for(int i=n;i>=1;--i)add(s[i]-‘a‘);
    for(int i=0;i<=cnt;++i){
        mx[i]=-oo;cmx[i]=-oo;
        mn[i]=oo;cmn[i]=oo;
    }
    int now=0;
    for(int i=n;i>=1;--i){
        int id=s[i]-‘a‘;
        now=st[now].next[id];
        sum[now]++;
        mx[now]=a[i];mn[now]=a[i];
    }
    for(int i=0;i<=cnt;++i)t[st[i].len]++;
    for(int i=1;i<=n;++i)t[i]+=t[i-1];
    for(int i=0;i<=cnt;++i)b[--t[st[i].len]]=i;
    for(int i=0;i<=n;++i)ans2[i]=-oo;
    for(int i=cnt;i>=0;--i){
        int v=b[i],u=st[v].link,R=st[v].len,L=st[u].len;

        LL tmp=-oo;
        if(cmx[v]!=-oo)tmp=max(tmp,mx[v]*cmx[v]);
        if(cmn[v]!=oo)tmp=max(tmp,mn[v]*cmn[v]);
        if(tmp!=-oo)ans2[R]=max(ans2[R],tmp);

        ans1[L]+=sum[u]*sum[v];

        sum[u]=sum[u]+sum[v];

        if(mx[v]>=mx[u]){cmx[u]=mx[u];mx[u]=mx[v];}
        else if(mx[v]>cmx[u])cmx[u]=mx[v];

        if(mn[v]<=mn[u]){cmn[u]=mn[u];mn[u]=mn[v];}
        else if(mn[v]<cmn[u])cmn[u]=mn[v];
    }
    for(int i=n-1;i>=0;--i)ans1[i]+=ans1[i+1];
    for(int i=n-1;i>=0;--i)ans2[i]=max(ans2[i],ans2[i+1]);
    for(int i=0;i<n;++i){
        if(!ans1[i])ans2[i]=0;
        printf("%lld %lld\n",ans1[i],ans2[i]);
    }return 0;
}

  

时间: 2024-12-22 15:58:13

BZOJ 4199 品酒大会的相关文章

[BZOJ]4199 品酒大会(Noi2015)

讲道理是后缀数组裸题吧,虽然知道后缀数组的原理但是小C不会写是什么鬼.. 小C趁着做这题的当儿,学习了一下后缀数组. 网络上的后缀数组模板完全看不懂怎么破,全程照着黄学长的代码抄,感觉黄学长写得还是很优雅的. 求LCP的部分已经崩坏了,小C自己脑补的做法是..倍增?? 看到正确的写法之后小C内心是绝望的,大致意思是:在原字符串中,设相邻两个后缀为Sx.Sx+1,那么有height[x+1]>=height[x]-1.(height数组就是小C代码里的tp数组) Description 一年一度的

bzoj 4199 &amp;&amp; NOI 2015 品酒大会

一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手"两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一.设 Str(l,r)Str(l,r) 表示第 ll 杯酒到第 rr 杯酒的 r?l+1

【BZOJ-4199】品酒大会 后缀数组 + 并查集合并集合

4199: [Noi2015]品酒大会 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 436  Solved: 243[Submit][Status][Discuss] Description 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 i

品酒大会(uoj 131)

一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手"两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1≤i≤n) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一.设 Str(l,r)Str(l,r) 表示第 ll 杯酒到第 rr 杯酒的 r?l+1

UOJ #131 【NOI2015】 品酒大会

题目链接:品酒大会 学了后缀自动机之后再来写这道题就轻松多了-- 首先,题面中的两杯酒\(r\)相似就是这两个后缀的最长公共前缀大于等于\(r\).把串翻转过来之后就变成了两个前缀的最长公共后缀--然后就是\(parent\)树的事了-- 接着,我们要求出选出两杯\(r\)相似的酒的方案数.这个比较显然,就是枚举两个节点的\(lca\),然后子树的\(right\)集合大小 两两乘起来就可以了. 然后就是选出两个值使得乘积最大.树型\(dp\)还是比较显然的,在\(parent\)树上记录一下每

品酒大会[NOI2015]

品酒大会[NOI2015] P2330 - [NOI2015]品酒大会 Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手"两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 n 杯鸡尾酒.这 n 杯鸡尾酒排成一行,其中第i杯酒(1≤i≤n)被贴上了一个标签 si,每个标签都是 26 个小写英文字母之一.设Str(l,r)表示

Uoj #131. 【NOI2015】品酒大会 后缀数组,并查集

#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 nn 杯鸡尾酒.这 nn 杯鸡尾酒排成一行,其中第 ii 杯酒 (1≤i≤n1in) 被贴上了一个标签 sisi,每个标签都是 2626 个小写英文字母之一.设 Str(l,r)Strlr 表示第 ll 杯酒到第 rr 杯酒的 

【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

[BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默水过~ 本题的实现还是非常简单的,先求出height数组,然后两杯酒'r'相似就等价于二者中间的height都>=r,于是我们将height排序,从大到小扔进去,那么所有连续的区间中的点对就都是相似的了.维护连续区间可以用并查集.统计点对个数需要维护size,统计最大乘积需要维护最(次)大(小)值,

[UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainbow 调制了 n杯鸡尾酒.这 n杯鸡尾酒排成一行,其中第 i杯酒 (1≤i≤n ) 被贴上了一个标签 si ,每个标签都是 26 个小写英文字母之一.设 Str(l,r)表示第 l杯酒到第 r 杯酒的 r−l+1 个标签顺次连接构成的字