首页 > 其他分享 >洛谷-P2178 学习笔记

洛谷-P2178 学习笔记

时间:2024-03-21 13:34:39浏览次数:35  
标签:memset 洛谷 int P2178 笔记 杯酒 MAXN sa sizeof

题面

[NOI2015] 品酒大会

题目描述

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

在大会的晚餐上,调酒师 Rainbow 调制了 \(n\) 杯鸡尾酒。这 \(n\) 杯鸡尾酒排成一行,其中第 \(n\) 杯酒 (\(1 ≤ i ≤ n\)) 被贴上了一个标签 \(s_i\) ,每个标签都是 \(26\) 个小写 英文字母之一。设 \(str(l, r)\) 表示第 \(l\) 杯酒到第 \(r\) 杯酒的 \(r - l + 1\) 个标签顺次连接构成的字符串。若 \(str(p, p_0) = str(q, q_0)\),其中 \(1 ≤ p ≤ p_0 ≤ n\), \(1 ≤ q ≤ q_0 ≤ n\), \(p ≠ q\),\(p_0-p+1 = q_0 - 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\)) 的 美味度为 \(a_i\) 。现在 Rainbow 公布了挑战环节的问题:本次大会调制的鸡尾酒有一个特点,如果把第 \(p\) 杯酒与第 \(q\) 杯酒调兑在一起,将得到一杯美味度为 \(a_p\times a_q\) 的 酒。现在请各位品酒师分别对于 \(r = 0,1,2,⋯,n-1\) ,统计出有多少种方法可以 选出 \(2\) 杯“ \(r\) 相似”的酒,并回答选择 \(2\) 杯“\(r\) 相似”的酒调兑可以得到的美味度的最大值。

输入格式

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

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

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

输出格式

包括 \(n\) 行。

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

样例 #1

样例输入 #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

样例输入 #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\) 。

【时限1s,内存512M】

简要题意

  • 长 \(n\) 的字符串 \(s\)。

  • 对于 \(r \in [0, n)\)

    • 求 \(\forall 1\le i < j \le n \space lcp(i, j) \ge r\) 的对数。

    • 以及 满足 \(lcp(i, j) \ge r\) 时 \(a_i \times a_j\) 的最大值。

思想

Step 1

看到 \(LCP\) 想到 \(Suffix\space Array\)。

问题转化成满足 \(\min \limits_{x=sa_i + 1}^{sa_j} height_x \ge r\) 的答案。

Step 2

大于等于很难受,我们把他转化成等于再做后缀和与最大值就行了。

问题转化成满足 \(\min \limits_{x=sa_i + 1}^{sa_j} height_x = r\) 的答案。

Step 3

要求一个区间内某最小值等于某值

经典套路

一般使用笛卡尔树或并查集。

这里使用并查集。

从大到小枚举height,每次把左右两个区间合并并计算答案。

Step 4

考虑合并的时候如何更新。

第一问的答案只有在横跨了枚举的值时才会产生贡献。

将左右区间的长度相乘即可。

第二问的答案就拿左边的最大最小,右边的最大最小乘,因为可能有负数。

Talk is cheap, show me the code

#include <bits/stdc++.h>
using namespace std;

constexpr int MAXN = 3e5 + 5;
constexpr long long INF = 0x3f3f3f3f3f3f3f3f;

int cnt[MAXN], oldrk[MAXN * 2], id[MAXN], key1[MAXN];

bool cmp(int x, int y, int w) {
    return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w];
}

struct SuffixArray {
    int n, sa[MAXN], rk[MAXN], height[MAXN];
    void init(string s) {
        memset(cnt, 0, sizeof cnt);
        memset(oldrk, 0, sizeof oldrk);
        memset(id, 0, sizeof id);
        memset(key1, 0, sizeof key1);
        memset(sa, 0, sizeof sa);
        memset(rk, 0, sizeof rk);
        memset(height, 0, sizeof height);
        n = int(s.size());
        int m = 27, p;
        s = " " + s;
        for (int i = 1; i <= n; i++)
            cnt[rk[i] = s[i] - 'a' + 1]++;
        for (int i = 1; i <= m; i++)
            cnt[i] += cnt[i - 1];
        for (int i = n; i >= 1; i--)
            sa[cnt[rk[i]]--] = i;

        for (int w = 1;; w <<= 1, m = p) {
            p = 0;
            for (int i = n; i > n - w; i--)
                id[++p] = i;
            for (int i = 1; i <= n; i++)
                if (sa[i] > w)
                    id[++p] = sa[i] - w;

            memset(cnt, 0, sizeof cnt);
            for (int i = 1; i <= n; i++)
                cnt[key1[i] = rk[id[i]]]++;
            for (int i = 1; i <= m; i++)
                cnt[i] += cnt[i - 1];
            for (int i = n; i >= 1; i--)
                sa[cnt[key1[i]]--] = id[i];

            memcpy(oldrk + 1, rk + 1, n * sizeof(int));
            p = 0;
            for (int i = 1; i <= n; i++) {
                if (cmp(sa[i], sa[i - 1], w))
                    rk[sa[i]] = p;
                else
                    rk[sa[i]] = ++p;
            }
            if (p == n)
                break;
        }

        for (int i = 1, k = 0; i <= n; i++) {
            if (rk[i] == 0)
                continue;
            if (k)
                k--;
            while (s[i + k] == s[sa[rk[i] - 1] + k])
                k++;
            height[rk[i]] = k;
        }
    }

    bool ask(int l, int r) {
        return height[l] > height[r];
    }
} sa;

int n;
string s;
int a[MAXN], idx[MAXN];
long long res1[MAXN], res2[MAXN];

struct Union {
    int n; // node sums
    int p[MAXN]; // parent
    long long ans[MAXN], mx[MAXN], mn[MAXN], sz[MAXN];

    void init(int _n) {
        n = _n;
        for (int i = 1; i <= n; i++)
            p[i] = i, sz[i] = 1, mx[i] = mn[i] = a[i], ans[i] = -INF;
    }

    int get(int x) {
        if (x == p[x])
            return x;
        return p[x] = get(p[x]);
    }

    void merge(int x, int y, int len) {
        x = get(x);
        y = get(y);
        p[y] = x;
        res1[len] += 1ll * sz[x] * sz[y];
        sz[x] += sz[y];
        ans[x] = max({ ans[x], ans[y], 1ll * mx[x] * mx[y], 1ll * mx[x] * mn[y], 1ll * mn[x] * mx[y], 1ll * mn[x] * mn[y] });
        mx[x] = max(mx[x], mx[y]);
        mn[x] = min(mn[x], mn[y]);
        res2[len] = max(res2[len], ans[x]);
    }
} u;

bool cmp2(int x, int y) {
    return sa.ask(x, y);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> s;
    for (int i = 1; i <= n; i++)
        cin >> a[i], idx[i] = i;

    u.init(n);

    sa.init(s);

    sort(idx + 2, idx + n + 1, cmp2);

    memset(res1, 0, sizeof res1);
    memset(res2, 0xc0, sizeof res2);

    for (int i = 2; i <= n; i++)
        u.merge(sa.sa[idx[i]], sa.sa[idx[i] - 1], sa.height[idx[i]]);

    for (int i = n - 1; i >= 0; i--)
        res1[i] += res1[i + 1];
    for (int i = n - 1; i >= 0; i--)
        res2[i] = max(res2[i], res2[i + 1]);

    for (int i = 0; i < n; i++) {
        cout << res1[i] << " ";
        if (res1[i] == 0)
            cout << 0 << endl;
        else
            cout << res2[i] << endl;
    }

        return 0;
}

运用到的知识点&Trick

SA(知识点)

\(Suffix\space Array\) 中后缀 \(i\) 与 后缀 \(j\) 的 \(LCP\) 为 \(\min \limits_{x=sa_i + 1}^{sa_j} height_x\)。

并查集(Trick)

求满足区间最小/最大值等于某数的答案。

从大往小/从小往大枚举最小/最大值并把左右区间合并计算答案。

标签:memset,洛谷,int,P2178,笔记,杯酒,MAXN,sa,sizeof
From: https://www.cnblogs.com/LightningCreeper/p/18087173

相关文章

  • 使用appuploder流程笔记
     1.如何没有账号去apple官网注册一个,地址:https://developer.apple.com/account2.下载解压appuploder,双击打开,用刚刚注册的账号登录,下载地址:http://www.applicationloader.net/(使用第一次后,可以点击记住密码即可一键登录)注意:未支付apple的账号需要勾选“未付苹果688”  ......
  • Java学习笔记——第二十二天
    Java高级技术单元测试概述单元测试就是针对最小的功能单元(方法),编写测试代码对该功能进行正确性测试。目前的测试方法是怎样的,存在什么问题只能编写main方法,并在main方法中再去调用其他方法进行测试。使用起来很不灵活,无法实现自动化测试。无法得到测试的报告,需要程序员......
  • 数字图像处理学习笔记(一)
    数字图像处理学习笔记(一)digital_image_process说明内容列表(已完成)第一章绪论第二章基本原理Matlab支持图片格式图像操作数据类图像类型数据类与图像数据类型间的转换数组索引例2.5标准数组运算符代码优化单元数组与结构体digital_image_process数字图像处理学习......
  • Asp-Net-Core开发笔记:实现动态审计日志功能
    前言最近一直在写Go和Python,好久没写C#,重新回来写C#代码时竟有一种亲切感~说回正题。在当今这个数字化迅速发展的时代,每一个操作都可能对业务产生深远的影响,无论是对数据的简单查询,还是对系统配置的修改。在这样的背景下,审计日志不仅仅是一种遵循最佳实践的手段,更是确......
  • Alize 声纹识别 学习笔记 失败了
    源码地址https://github.com/ALIZE-Speaker-Recognition/alize-corehttps://github.com/ALIZE-Speaker-Recognition/LIA_RALhttps://gitcode.com/ibillxia/VoicePrintReco/tree/master项目目录目录简介LIA_RAL_2.0里面为了更好地满足每个人的需求,ALIZÉ采用了多层架构。......
  • Alize 声纹识别 学习笔记2 失败了
    alize源码https://github.com/ALIZE-Speaker-Recognition/alize-corehttps://github.com/ALIZE-Speaker-Recognition/LIA_RALLIA_RAL提供了四个官方例子https://alize.univ-avignon.fr/https://alize.univ-avignon.fr/doc/01_GMM-UBM_system_with_ALIZE3.0.tar.gzhttps://......
  • WinClip非官方复现代码学习笔记2
    一、数据集加载1.数据集放置将下载的数据集解压到datasets文件夹的下面,方便后续操作。2.数据集预处理数据集预处理针对两个数据集给了两个不同的预处理指令,我测试了VISA数据集,以下是我对VISA数据集的实例。1.datasets/prepare_visa_public.py文件配置打开这个文件,第1......
  • 推荐系统实现-笔记(2)
    推荐系统实现(1)推荐系统Demo实现笔记:系统概述本推荐系统采用基于内容的推荐算法,旨在为用户提供与其已收藏内容相似的新内容推荐。系统设立了两级过滤机制,以提高推荐的准确性和实用性。第一级过滤根据语料自身的标签进行推荐,第二级过滤则基于第一级过滤得到的标签,计算每个类别中......
  • 洛谷题单指南-集合-P1102 A-B 数对
    原题链接:https://www.luogu.com.cn/problem/P1102题意解读:前文https://www.cnblogs.com/jcwy/p/18043197介绍了二分和双指针的做法,本文介绍hash的做法。解题思路:定义map<int,int>h,保存每个数+c出现的个数同样,先将所有数由小到大哦排序遍历每一个数x,答案累加ans+=h[x]然......
  • C#笔记-异常处理
    一、引言1、什么是异常异常是程序运行时发生的不正常或错误情况。异常会打断程序的正常流程,导致程序终止或产生不可预测的结果。2、为什么要处理异常提高程序的健壮性和稳定性。提供友好的错误提示,提升用户体验。方便开发者定位和修复问题二、C#中的异常处理机制1、tr......