首页 > 其他分享 >CF1801C 做题笔记

CF1801C 做题笔记

时间:2023-10-12 20:55:07浏览次数:30  
标签:乐曲 片段 CF1801C 200005 idx int 笔记 dp

题目链接

一道需要挖掘一些性质的 dpt,居然独立想出来了。

本蒟蒻太菜了只会树状数组的做法,单调栈不会。

先考虑只管对答案有贡献的音乐,这当然是正确的,因为我们可以把对答案没有贡献的音乐放到最后。

对于每一首乐曲,我们也能对它进行一个简单的处理来模拟听的过程,维护一个值 $lst$,每次输入的数 $x$ 如果大于 $lst$,那么听了这个片段后答案就会加一,将 $x$ 存入数组中,否则忽略它。

假设每个音乐的好听程度为其中最美妙的片段。

处理后有一个可以感性理解的结论:无论当前听过的最好听的片段是什么,听了一首乐曲,能够使答案增加的一定是存入数组中的片段。

证明考虑反证,假设当前听过最好听的片段好听值为 $mx$,现在听乐曲 $i$,能够找到一个位置使得 $a_{i,j} \geq mx$ 且 $a_{i,j}$ 被忽略。这是显然不可能得一件事,因为如果 $a_{i,j}$ 被忽略,就说明前面有一个更好听的片段,而 $mx$ 应该先听到的是更好听的片段就忽略了 $a_{i,j}$。

再来想,有答案贡献的音乐放在一起,每个音乐的好听程度一定是递增的。

做法于是很显然了,先将所有音乐按照好听程度排序,设 $f_i$ 为考虑第 $1$ 个音乐到第 $i$ 个音乐,其中第 $i$ 个音乐必须选的最大答案,设 $mx_j$ 为第 $j$ 首乐曲的好听程度,那么大体结构就是枚举前一个听的乐曲 $j$,然后再算出听 $i$ 之后的答案,所有的取个 $\max$ 即可。

上述为 $O(n^2)$ 做法,很烂,会超时,貌似可以用单调栈优化,超时原因是没有用到 $\sum k_i \leq 200000$ 这个条件。

考虑对于每一个乐曲的转移改为枚举这个乐曲中的每一个没被忽略的片段,然后去找前面的某个乐曲 $j$,使得 $j$ 的好听程度 $<$ 这个片段的美妙值,然后就能从 $dp_j$ 转移过来,再听这个片段以及这个片段后面没有被忽略的。

很绕口,读不懂多读几遍,然后这是个单点修改求前缀最值可以用树状数组优化到 $O(n\log n)$。

代码:

#include <bits/stdc++.h>
#define int long long
#define For(i, a, b) for (int i = (a); i <= (b); i ++)
#define foR(i, a, b) for (int i = (a); i >= (b); i --)
using namespace std;
int n, x, cnt;
int c[200005], dp[200005], idx[200005];
vector <int> a[200005];
vector <int> v[200005];
void add (int x, int y) {for (; x <= 200000; x += x & -x) c[x] = max (c[x], y);}
int query (int x) {return (x == 0 ? 0 : max (query (x - (x & -x) ), c[x]) );}
void clear (int x) {for (; x <= 200000; x += x & -x) c[x] = 0;}
set <int> s;
void solve () {
    s.clear ();
    scanf ("%lld", &n);
    For (i, 1, n) {
        scanf ("%lld", &cnt);
        int last = 0;
        while (cnt --) {
            scanf ("%lld", &x);
            if (x > last) {
                a[i].push_back (x);
                last = x;
            }
        }
        s.insert (last);
        v[last].push_back (i);
    }
    cnt = 0;
    for (int i : s) for (int j : v[i]) idx[++ cnt] = j;
    int ans = 0;
    For (i, 1, n) {
        for (int j = 0; j < a[idx[i] ].size (); j ++)
            dp[i] = max (dp[i], query (a[idx[i] ][j] - 1) + (long long) (a[idx[i] ].size () ) - j);
        add (a[idx[i] ].back (), dp[i]);
        ans = max (ans, dp[i]);
    }
    cout << ans;
    For (i, 1, n) {
        clear (a[i].back () );
        v[a[i].back ()].clear ();
        a[i].clear ();
        dp[i] = 0;
    }
}
signed main () {
    int _ = 1;
    cin >> _;
    while (_ --) {
        solve ();
        cout << '\n';
    }
    return 0;
}

 

标签:乐曲,片段,CF1801C,200005,idx,int,笔记,dp
From: https://www.cnblogs.com/Xy-top/p/17760529.html

相关文章

  • Kruskal重构树 学习笔记
    前言也许在看这篇文章之前,你可以看看这篇文章?前置知识:\(kruskal\)求最小生成树,并查集……算法介绍问题引入两个点之间的所有简单路径上最大边权的最小值。我们定义\(u\tov\)路径的瓶颈为,路径上的边权最大值。那么下图的瓶颈就为4:同时一条路径也可能有多个瓶颈,求最......
  • 笔记软件快捷键
    Ctrl+shift+【有序列表Ctrl+shift+】无须列表标题:Ctrl+1/2/3/4/5标题大小Ctrl+0段落增大标题级别:Ctrl++减小标题级别:Ctrl+-增加缩进Ctrl+]减少缩进Ctrl+]选中一整行:CTRL+L选中单词:CTRL+D选中相同格式的文字:ctrl+E跳转到文章开头:CTRL+Home跳转到文章结尾:CTRL+e......
  • 动态规划——树形DP 学习笔记
    动态规划——树形DP学习笔记引入前置知识:树基础。树形DP,即在树上进行的DP,最常见的状态表示为\(f_{u,\cdots}\),表示以\(u\)为根的子树的某个东东。本文将讲解一些经典题目(树的子树个数、树的最大独立集、树的最小点覆盖、树的最小支配集、树的直径、树的重心、树的中心),以......
  • 2023/10/12 学习笔记2
    一、信号与数制转换1.1 信号相关概念1.1.1 信息:不同领域对信息有不同的定义,一般认为信息是人们对现实世界事物的存在方式或运动状态的某种认识。表示信息的形式可以是数值、文字、图形、声音、图像及动画等。1.1.2 数据:数据是用于描述事物的某些属性的具体量值。1.1.......
  • docker 部署.net core ,用于博主本人笔记
     安装dockerdocker部署netcore步骤1、下载最新netcore支持dockerpullmcr.microsoft.com/dotnet/core/aspnet:latest2、发布netcore项目linux环境需要在发布文件夹内创建Dockerfile,并添加如下内容--------------------------以下为dockerFile内容--------------------......
  • 二次离线莫队笔记
    前言莫队可以解决许多其他数据结构无法完成的问题,正在很多其他问题上也可以拿部分分甚至满分,只因其复杂度为小常数\(O(n\sqrtn\timesk)\)其中\(k\)是单次扩张以及收缩的复杂度,而二离莫队可以在答案可差分的情况下达到\(O(n\sqrtn+n\timesk)\)起源lxl把二次离线莫......
  • 网络流笔记
    前言粗略地讲一下吧,大概能理解就行理论部分借鉴了oi-wiki,有问题欢迎指出网络流网络是一个特殊有向图$G=(V,E)$,特殊在于有源点$s$和汇点$t$首先网络流图中每条边$(u,v)$都有一个容量$c(u,v)$介绍流函数$f(u,v)$,指$u$到$v$流量所以就会有流量守恒,即$0\leq......
  • 《信息安全系统设计与实现》第六周学习笔记
    一、课程内容第十一章学习EXT2文件数据结构1、通过mkfs创建虚拟磁盘mke2fs[-bblksize-Nninodes]devicenblocks虚拟磁盘布局:2、操作系统内核中的文件系统函数3、系统调用4、I/O库函数5、用户命令6、sh脚本低级别的文件操作中的常用函数:打开和关闭文件:open():打......
  • DR7808 配置笔记
    CSA部分:内部CSA可以配置为单向,或者双向,一共有两个CSA,内部CSA的GAIN可以配置,挡位有10,20,40,80四种增益选项。也可以直接关闭内部CSA,CSA的过流保护值和过流保护滤波时间都可以单独设置。相关寄存器:DR7808_GENCTRL1DR7808_HBIDIAGDR7808_GENCTRL2DR7808_CSA_OC_SH寄存器相关描......
  • C#学习笔记--面向对象三大特征
    C#核心面向对象--封装用程序来抽象现实世界,(万物皆对象)来编程实现功能。三大特性:封装、继承、多态。类与对象声明位置:namespace中样式:class类名{}命名:帕斯卡命名法(首字母大写)实例化对象:根据类来新建一个对象。Personp=newPerson();成员变量声明在类语句块中用来描述......