2024牛客多校2I Red Playing Cards
本文同步于我的博客。
Problem
There are \(2\cdot n\) cards arranged in a row, with each card numbered from \(1\) to \(n\) having exactly 2 copies.
Each time, Red can choose a subarray of consecutive cards (at least \(2\) cards) to remove from the deck. The chosen subarray must satisfy that the first and last cards have the same number. The score for this operation is: the number of cards multiplied by the number on the first card. Now Red wants to know what is the maximum value of the final score?
给你一个长度为 \(2n\) 的数组,\(1\) 到 $ n$ 每个数字恰好出现两次。你可以进行这样的操作:选择两个相同的数字 \(x\) (必须都还存在于数组中),将这两个数以及其间的所有数字(共计 \(cnt\) 个)全部拿走,并获得 \(x\cdot cnt\) 得分。求最终最多能够获得多少分?
\(1\le n\le 3\times 10^3\)
Solution
我们发现基本有这三种情况:
- 相离。比如
1 1 3 3,1和3互不影响。 - 包含。比如
1 3 3 1,可以先拿3-3再拿1-1,也可以直接一次拿1-1,此时3没有任何贡献。 - 相交。比如
1 3 1 3,如果拿了1-1就不能再拿3-3了,拿了3-3也不能再拿1-1。
设 \(f(i)\) 为 \([l_i,r_i]\) 这段区间的最大得分。\(l_i,r_i\) 分别指第一个 \(i\) 和第二个 \(i\) 的位置。
先假设 \([l_i,r_i]\) 中每个数字的贡献都是 \(i\),而如果遇到了另一个区间 \([l_j,r_j]\) 满足 \((l_i<l_j<r_j<r_i)\),那么考虑使用 \(f(j)\) 来代替这一个子区间的贡献。
这里一定有 \(len_j<len_i\),所以我们按照区间长度 \(len_i\) 排序来计算 \(f(i)\)
那么如何计算 \(f(i)\) 呢?
设 \(g(k)\) 表示,在计算 \(f(i)\) 时,区间 \([l_i,k]\) 的最大贡献。
- 对于一般情况而言,\(g(k)=g(k-1)+i\)。
- 而如果当前 \(k\) 是某个数字 \(j\) 的第二次出现的地方,且这个数字第一次出现的地方 \(l_j\in[l_i,k]\),那么需要考虑有可能先抹去 \(j\) ,也就是取 \([l_j,r_j]\) 得分为 \(f(j)\),会使得答案更优,。
g(k)=\left\{
\begin{array}{l}
\max \left(g(k-1)+i, g\left(l_j-1\right)+f(j)\right), \text { if } k=r_j \text { and } l_j>l_i \\
g(k-1)+i, \text { otherwise }
\end{array}\right.
\end{gather}
\]
而我们需要的 \(f(i)=g(r_i)\)。
为了得到整个数组的得分,这里有个trick。我们在数组前后添加两个0,求 \(f(0)\) 即可。
时间复杂度 \(O(n^2)\)。
Code
/**************************************************************
* Problem:
* Author: Vanilla_chan
* Date:
* E-Mail: heshaohong2015@outlook.com
**************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
#ifdef ONLINE_JUDGE
char buf[1<<23],* p1=buf,* p2=buf,obuf[1<<23],* O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
using namespace std;
#define N 6010
int n;
int a[N],l[N],r[N],len[N];
bool cmp(int x,int y)
{
return len[x]<len[y];
}
vector<int>p;
int f[N],g[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
// cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n*2;i++)
{
cin>>a[i];
if(l[a[i]])
{
r[a[i]]=i;
len[a[i]]=i-l[a[i]]+1;
}
else l[a[i]]=i;
}
l[0]=0,r[0]=2*n+1,len[0]=2*n+2;
for(int i=0;i<=n;i++)
{
p.push_back(i);
}
sort(p.begin(),p.end(),cmp);
// for(int x=0;x<=n;x++) cout<<p[x]<<" "; cout<<endl;
for(auto x:p)
{
for(int k=l[x];k<=r[x];k++)
{
g[k]=g[k-1]+x;
int y=a[k];
if(k==r[y]&&l[y]>l[x])
{
g[k]=max(g[k],g[l[y]-1]+f[y]);
}
}
f[x]=g[r[x]];
for(int k=l[x];k<=r[x];k++) g[k]=0;
// cout<<"f["<<x<<"]="<<f[x]<<endl;
}
cout<<f[0]<<endl;
}
return 0;
}
2024牛客多校2I Red Playing Cards的更多相关文章
- 2019牛客多校第一场 I Points Division(动态规划+线段树)
2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...
- 牛客多校第一场 B Inergratiion
牛客多校第一场 B Inergratiion 传送门:https://ac.nowcoder.com/acm/contest/881/B 题意: 给你一个 [求值为多少 题解: 根据线代的知识 我们可 ...
- 2019牛客多校第二场 A Eddy Walker(概率推公式)
2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...
- 牛客多校第三场 F Planting Trees
牛客多校第三场 F Planting Trees 题意: 求矩阵内最大值减最小值大于k的最大子矩阵的面积 题解: 矩阵压缩的技巧 因为对于我们有用的信息只有这个矩阵内的最大值和最小值 所以我们可以将一 ...
- 牛客多校第三场 G Removing Stones(分治+线段树)
牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...
- 牛客多校第四场sequence C (线段树+单调栈)
牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...
- 牛客多校第3场 J 思维+树状数组+二分
牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...
- 2019牛客多校第八场 F题 Flowers 计算几何+线段树
2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...
- 2019年牛客多校第一场B题Integration 数学
2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...
- 2020牛客多校第八场K题
__int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...
随机推荐
- Jmeter tcp 返回500,但服务器收到请求
解决方法:再end of line(Eol)bytes value 正确写上报文最后两位十进制字节码
- nuclei安装使用
go环境安装 go 下载路径:https://golang.google.cn/dl/ 1.双击 go1.20.7.windows-amd64.msi 2.点击下一步 3.我同意,然后下一步. 4.选 ...
- 【面试题】实现 queryParse 函数,完成解析 URL 参数的功能
问题:实现 queryParse 函数,完成解析 URL 参数的功能 /** * 问题:实现 queryParse 函数,完成解析 URL 参数的功能 * * 用法: * ```js * const ...
- 一文搞懂 Redis 架构演化之路
作者:ryetan,腾讯 CSIG 后台开发工程师 现如今 Redis 变得越来越流行,几乎在很多项目中都要被用到,不知道你在使用 Redis 时,有没有思考过,Redis 到底是如何稳定.高性能地提 ...
- SetupFactory-脚本
1.写注册表 lResult = Registry.DoesKeyExist(HKEY_LOCAL_MACHINE, "SOFTWARE\\MapInfo\\MapX\\5.0") ...
- [源码系列:手写spring] IOC第一节:简单bean容器
本专栏带领大家手写一遍spring的核心代码,包括IOC,AOP,三级缓存... 第一节较为简单,后面的章节会逐渐提升代码量和复杂度,喜欢的同学记得订阅哦  ̄▽ ̄ 定义一个简单的bean容器BeanF ...
- unigui显示websocket服务端向客户端发送信息【15】
用WebSocket从服务端直接发送消息给all客户端. 1.在ServerModule 放TUniThreadTimer 2.timer event: procedure TUniServerMod ...
- WCHNET_SocketSend返回0x11原因及解决方法
问题描述: TCPCLIENT模式使用WCHNET_SocketSend发送有概率会返回0x11 按wchnet.h定义为内存溢出错误. 异常分析: 通过WCHNET_QueryUnack查看,发现异 ...
- Lua中获取第二天凌晨的剩余时间
在时间这个问题上,lua提供两大方法来供开发者使用,一个是os.time(),一个是os.date(),这两大方法可以满足日常开发的需求. 那么我们如何准确运用这两大方法呢. 在这一文章中我们先讲os ...
- Python科学计算系列5—导数
1.一元函数的导数 例1:求下列函数的导数 例2:求下列函数的50阶导数 代码如下: from sympy import * x = symbols('x') f1 = diff(tan(x)) f2 ...