zoukankan      html  css  js  c++  java
  • [NOI2015]品酒大会

    题目描述

    一年一度的“幻影阁夏日品酒大会”隆重开幕了。大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加。

    在大会的晚餐上,调酒师 Rainbow 调制了 n 杯鸡尾酒。这 n 杯鸡尾酒排成一行,其中第 n 杯酒 (1 ≤ i ≤ n) 被贴上了一个标签si,每个标签都是 26 个小写 英文字母之一。设 str(l, r)表示第 l 杯酒到第 r 杯酒的 r − l + 1 个标签顺次连接构成的字符串。若 str(p, po) = str(q, qo),其中 1 ≤ p ≤ po ≤ n, 1 ≤ q ≤ qo ≤ n, p ≠ q, po − p + 1 = qo − q + 1 = r ,则称第 p 杯酒与第 q 杯酒是“ r 相似” 的。当然两杯“ r 相似”(r > 1)的酒同时也是“ 1 相似”、“ 2 相似”、……、“ (r − 1) 相似”的。特别地,对于任意的 1 ≤ p , q ≤ n , p ≠ q ,第 p 杯酒和第 q 杯酒都 是“ 0 相似”的。

    在品尝环节上,品酒师 Freda 轻松地评定了每一杯酒的美味度,凭借其专业的水准和经验成功夺取了“首席品酒家”的称号,其中第 i 杯酒 (1 ≤ i ≤ n) 的 美味度为 ai 。现在 Rainbow 公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点,如果把第 p 杯酒与第 q 杯酒调兑在一起,将得到一杯美味度为 ap*aq 的 酒。现在请各位品酒师分别对于 r = 0,1,2, ⋯ , n − 1 ,统计出有多少种方法可以 选出 2 杯“ r 相似”的酒,并回答选择 2 杯“ r 相似”的酒调兑可以得到的美味度的最大值。

    输入输出格式

    输入格式:

    第 1 行包含 1 个正整数 n ,表示鸡尾酒的杯数。

    第 2 行包含一个长度为 n 的字符串 S,其中第 i 个字符表示第 i 杯酒的标签。

    第 3 行包含 n 个整数,相邻整数之间用单个空格隔开,其中第 i 个整数表示第 i 杯酒的美味度 ai 。

    输出格式:

    包括 n 行。第 i 行输出 2 个整数,中间用单个空格隔开。第 1 个整 数表示选出两杯“ (i − 1) 相似”的酒的方案数,第 2 个整数表示选出两杯 “ (i − 1) 相似”的酒调兑可以得到的最大美味度。若不存在两杯“ (i − 1) 相似” 的酒,这两个数均为 0 。

    输入输出样例

    输入样例#1: 复制
    10
    ponoiiipoi
    2 1 4 7 4 8 3 6 4 7
    输出样例#1: 复制
    45 56
    10 56
    3 32
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0
    输入样例#2: 复制
    12
    abaabaabaaba
    1 -2 3 -4 5 -6 7 -8 9 -10 11 -12
    
    输出样例#2: 复制
    66 120
    34 120
    15 55
    12 40
    9 27
    7 16
    5 7
    3 -4
    2 -4
    1 -4
    0 0
    0 0

    说明

    【样例说明 1】

    用二元组 (p, q) 表示第 p 杯酒与第 q 杯酒。

    0 相似:所有 45 对二元组都是 0 相似的,美味度最大的是 8 × 7 = 56 。

    1 相似: (1,8) (2,4) (2,9) (4,9) (5,6) (5,7) (5,10) (6,7) (6,10) (7,10) ,最大的 8 × 7 = 56 。

    2 相似: (1,8) (4,9) (5,6) ,最大的 4 × 8 = 32 。

    没有 3,4,5, ⋯ ,9 相似的两杯酒,故均输出 0 。

    问题转化为分别求LCP>=r的后缀的组数

    lcp为L的一组 对后面的L-1 L-2 L-3....也可以贡献

    求出每个height

    实际上对于每个(i,j),他的lcp都应当统计

    可以单独考虑每个height的贡献

    L[i]表示最靠左的不大于它的位置

    R[i]表示最靠右的大于它的位置(避免重复计算)

    那么height[i]的贡献就是(i-L[i]+1)*(R[i]-i+1)

    对于第二问,对左右取最大值相乘,再取最小值相乘,用ST表

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 lol ans[300001],sum[300001];
      9 int n,m;
     10 lol Min[300001][21],Max[300001][21],w[300001];
     11 int c[300001],x[300001],y[300001];
     12 int SA[300001],rank[300001],s[300001],h[300001],Log[300001];
     13 lol st[300001],L[300001],R[300001];
     14 char ch[300001];
     15 void radix_sort()
     16 {int i;
     17   for (i=0;i<=m;i++)
     18     c[i]=0;
     19   for (i=1;i<=n;i++)
     20     c[x[y[i]]]++;
     21   for (i=2;i<=m;i++)
     22     c[i]+=c[i-1];
     23   for (i=n;i>=1;i--)
     24     SA[c[x[y[i]]]--]=y[i];
     25 }
     26 void build_SA()
     27 {int i,j,k,p;
     28   for (i=1;i<=n;i++)
     29     x[i]=s[i],y[i]=i;
     30   m=100000;
     31   radix_sort();
     32   for (k=1;k<=n;k<<=1)
     33     {
     34       p=0;
     35       for (i=n-k+1;i<=n;i++)
     36     y[++p]=i;
     37       for (i=1;i<=n;i++)
     38     if (SA[i]>k) y[++p]=SA[i]-k;
     39       radix_sort();
     40       p=1;swap(x,y);
     41       x[SA[1]]=1;
     42       for (i=2;i<=n;i++)
     43     x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&(y[SA[i]+k]==y[SA[i-1]+k]))?p:++p;
     44       if (p>=n) break;
     45       m=p;
     46     }
     47   for (i=1;i<=n;i++)
     48     rank[SA[i]]=i;
     49   int L=0;
     50   for (i=1;i<=n;i++)
     51     {
     52       if (L>0) L--;
     53       j=SA[rank[i]-1];
     54       while (i+L<=n&&j+L<=n&&(s[j+L]==s[i+L])) L++;
     55       h[rank[i]]=L;
     56     }
     57 }
     58 lol rmq_max(int x,int y)
     59 {
     60   int L=Log[y-x+1];
     61   return max(Max[x][L],Max[y-(1<<L)+1][L]);
     62 }
     63 lol rmq_min(int x,int y)
     64 {
     65   int L=Log[y-x+1];
     66   return min(Min[x][L],Min[y-(1<<L)+1][L]);
     67 }
     68 int main()
     69 {lol i,j;
     70   int top;
     71   cin>>n;
     72   cin>>ch;
     73   for (i=1;i<=n;i++)
     74     {
     75       s[i]=(int)ch[i-1];
     76     }
     77   for (i=1;i<=n;i++)
     78     {
     79       scanf("%lld",&w[i]);
     80     }
     81   build_SA();
     82   for (i=1;i<=n;i++)
     83     Min[i][0]=Max[i][0]=w[SA[i]];
     84   for (j=1;(1<<j)<=n;j++)
     85     {
     86       for (i=1;i<=n-(1<<j)+1;i++)
     87     {
     88       Max[i][j]=max(Max[i][j-1],Max[i+(1<<j-1)][j-1]);
     89       Min[i][j]=min(Min[i][j-1],Min[i+(1<<j-1)][j-1]);
     90     }
     91     }
     92   for (i=1;i<=n;i++)
     93     {
     94       while (top&&h[i]<=h[st[top]]) top--;
     95       if (top==0) L[i]=1;
     96       else L[i]=st[top]+1;
     97       st[++top]=i;
     98     }
     99   Log[1]=0;
    100   for (i=2;i<=n;i++)
    101     Log[i]=Log[i/2]+1;
    102   top=0;
    103   for (i=n;i>=1;i--)
    104     {
    105       while (top&&h[i]<h[st[top]]) top--;
    106       if (top==0) R[i]=n;
    107       else R[i]=st[top]-1;
    108       st[++top]=i;
    109     }
    110   for (i=0;i<=n;i++)
    111     ans[i]=-2e18;
    112   for (i=1;i<=n;i++)
    113     {
    114       sum[h[i]]+=1ll*(R[i]-i+1)*(i-L[i]+1);
    115       ans[h[i]]=max(ans[h[i]],rmq_max(L[i]-1,i-1)*rmq_max(i,R[i]));
    116       ans[h[i]]=max(ans[h[i]],rmq_min(L[i]-1,i-1)*rmq_min(i,R[i]));
    117     }
    118   for (i=n-2;i>=0;i--)
    119     {
    120       sum[i]+=sum[i+1];
    121       ans[i]=max(ans[i],ans[i+1]);
    122     }
    123   sum[0]=(n-1)*n/2;
    124   for (i=0;i<=n-1;i++)
    125     printf("%lld %lld
    ",sum[i],ans[i]==-2e18?0:ans[i]);
    126 }
  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8512303.html
Copyright © 2011-2022 走看看