CF2029C New Rating
思路(二分 + 数据结构优化DP)
大致题意为:一个值 \(x\) 初始为 \(0\),然后有一个数组 \(a\),遍历一次数组。
如果 \(a_i > x\),则 \(x + 1\)。
如果 \(a_i < x\),则 \(x - 1\)。
如果 \(a_i = x\),则 \(x\) 不变。
必须且只能跨越一段连续区间,求 \(x\) 的最大可能值。
后面的由前面的计算得到,并且前面的不受后面的影响,并且必须跳跃一段,很容易想到 DP。
首先是 DP 状态。
最优解是开三个状态来 DP,这个官方题解讲得很清楚,因此这里提供一个我赛时写的两个状态的思路。
根据题目描述,可以连续也可以跳跃。
因此我选择给每个点 \(i\) 设两个状态:\(i\) 由前一个转移得到和由更前面的跳跃得到。
以下用 \(dp_{i, 0}\) 表示第 \(i\) 个点是由前面跳跃得到的,用 \(dp_{i, 1}\) 表示第 \(i\) 个点是由前一个点转移得到。
首先我们可以预处理一下一次也不跳的时候,每一个点的答案是多少,把它存入 \(dp_{i, 1}\) 中。这个很简单,按照题意从前往后模拟一遍即可。
然后我们考虑要跳跃的,也就是 \(dp_{i, 0}\) 的值。
因为题目要我们只能跳一次,所以,跳跃后的值只能通过没有跳过的值来转移,也就是 \(dp_{j, 1}\) 的值。
那么问题来了,只要和 \(i\) 有间隔的前面的点都可以作为转移的前置状态,选哪一个呢?
题目要我们求的是最后结果的最大值,不难发现,贪心地想,最后结果要最大,每一个局部的结果也要尽可能大。
因为这样的话,在 \(i\) 之后,经历相同的增增减减,在最后的答案一定会更大。
于是我们只有在这个点是增的时候才会更优,也就是在前面选择一个 \(dp_{i, 0}\) 的值比 \(a_i\) 小的点来转移。
(简单证明:如果 \(dp_{j, 1} \geq a_i\),因为是从0增上来的,那么一定可以在 \(j\) 之前找到一个 \(k\),满足 \(dp_{k, 1} < a_i\),证毕。)
又因为结果要尽可能的大,所以要在更小的点中选一个最大的。
那么转移方程就出来了:\(dp_{i, 0} = \max(dp_{j, 1} + 1)\),\(j\) 满足 \(j < i - 1\) 并且 \(dp_{j, 1} < a_i\)。
不难发现,如果暴搜的话,这样的复杂度是 \(O(n ^ 2)\) 的。
那再细品一下这句话:“比 \(a_i\) 更小的点中挑一个最大的。”那不就可以二分了吗。
我们可以把 \(j \in [1, i - 2]\) 的 \(dp_{j, 1}\) 的值以及 \(0\) 压入一个便于二分数据结构中,比如 map 或 set。
我赛时使用的树状数组(赛后发现 set 或者 map 就可以了而且复杂度更优)。
每次转移时,二分找到小于 \(a_i\) 中最大的一个值,用来转移得到 \(dp_{i, 0}\)。
这个过程可以在循环的过程中同时进行,每次处理完一个 \(i\) 的 \(dp_{i, 0}\) 后将 \(dp_{i - 1, 0}\) 压入数据结构即可。
到这里,我们就处理出了每一个点不跳跃到达和只跳跃一次到达能够得到的最大值。
要得到最后答案,我们还需要从前往后来一轮 DP。
这里我们再开一个 DP 数组 \(ans\)。
\(ans_{i, 1}\) 表示到 \(i\) 为止没有跳跃过得到的最大值。
\(ans_{i, 0}\) 表示到 \(i\) 为止跳跃过了到的最大值。
那么转移也很明显。
因为 \(dp_{i, 1}\) 预处理的就是到 \(i\) 为止没有跳跃过,所以 \(ans_{i, 1} = dp_{i, 1}\)。
而 \(ans_{i, 0}\) 因为表示的是到 \(i\) 为止跳跃过,所以我们只需要把在跳跃到 \(i\) 前面的位置和刚好跳跃得到 \(i\) 这个位置的结果取个最大值。
也就是假设跳跃到前面再不跳跃到 \(i\) 的答案设为 \(now\)。
如果 \(ans_{i - 1, 0} < a_i\),\(now = ans_{i - 1, 0} + 1\)。
如果 \(ans_{i - 1, 0} > a_i\),\(now = ans_{i - 1, 0} - 1\)。
如果 \(ans_{i - 1, 0} = a_i\),\(now = ans_{i - 1, 0}\)。
所以 \(ans_{i, 0} = \max(now, dp_{i, 0})\)。
这里要特别注意一下,如果 \(i = 1\),\(ans_{1, 0}\) 应设置为一个极小值,因为 \(1\) 这个点是不能通过跳跃得到的,这个状态不存在。
最后取答案的时候,其实就是 \(i \in [1, n - 1]\) 时,和 \(ans_{i, 1}\) 取最小,表示前面都不跳,后面全跳。\(i = n\) 时,和 \(ans_{n, 0}\) 取最小,表示在前面已经跳跃过了并且到达了 \(n\) 这个点。
时间复杂度 \(O(n \times \log{n})\)。
写题解的时候又想了一下,其实数据结构也可以不用,只需要记录到 \(i - 1\) 这个点时 \(dp_{j, 1}\) 的最大值就行了,因为是从 \(0\) 增长上来的,那么从 \(0\) 到 \(\max(dp_{j, 1})\) 之间的数一定都出现过,这样的话 \(O(n)\) 就可以了。
AC CODE
#include <bits/stdc++.h>
#define int long long
#define inf 2e18
#define ull unsigned long long
#define ls o << 1
#define rs o << 1 | 1
using namespace std;
const int N = 3e5 + 9;
int a[N];
int dp[N][2];
int ans[N][2];
int t[N];
int n;
int lowbit(int x){return x & -x;}
void add(int v, int x)
{
for(int i = v;i <= n;i += lowbit(i))t[i] += x;
}
int query(int v)
{
int res = 0;
for(int i = v;i;i -= lowbit(i))res += t[i];
return res;
}
void init()
{
for(int i = 1;i <= n;i ++)t[i] = 0;
for(int i = 1;i <= n;i ++)
{
dp[i][0] = dp[i][1] = 0;
ans[i][0] = ans[i][1] = 0;
}
}
void solve()
{
cin >> n;
init();
for(int i = 1;i <= n;i ++)cin >> a[i];
int now = 0;
for(int i = 1;i <= n;i ++)//预处理不跳跃的情况
{
if(a[i] > now)dp[i][1] = ++ now;
else if(a[i] == now)dp[i][1] = now;
else if(a[i] < now)dp[i][1] = -- now;
}
add(0 + 1, 1);
for(int i = 2;i <= n;i ++)//得到跳到i这个位置的dp值
{
int pre = query(a[i]);
int l = 0, r = a[i] + 1;
while(l + 1 != r)//二分找最优(用set或map更优)
{
int mid = (l + r) >> 1;
if(query(mid) < pre)l = mid;
else r = mid;
}
dp[i][0] = r;
add(dp[i - 1][1] + 1, 1);//将i - 1的没跳跃的dp值压入数据结构
}
for(int i = 1;i <= n;i ++)//处理到每个点为止的最优答案
{
ans[i][1] = dp[i][1];
if(i == 1)ans[i][0] = -inf;
else
{
int now = ans[i - 1][0];
if(now > a[i])now --;
else if(now < a[i])now ++;
ans[i][0] = max(now, dp[i][0]);
}
}
int res = 0;
for(int i = 1;i < n;i ++)res = max(res, ans[i][1]);//跳最后一段
res = max(res, ans[n][0]);//跳前面的
cout << res << '\n';
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t = 1;cin >> t;
while(t --)solve();
return 0;
}
CF2029C New Rating的更多相关文章
- Codefroces 750C:New Year and Rating(思维)
http://codeforces.com/contest/750/problem/C 题意:有n场比赛,每场比赛有一个c,代表比赛结束后分数的增长情况,有一个d,代表这场比赛在div1或者div2打 ...
- AngularJs的UI组件ui-Bootstrap分享(十二)——Rating
Rating是一个用于打分或排名的控件.看一个最简单的例子: <!DOCTYPE html> <html ng-app="ui.bootstrap.demo" x ...
- 从Elo Rating System谈到层次分析法
1. Elo Rating System Elo Rating System对于很多人来说比较陌生,根据wikipedia上的解释:Elo评分系统是一种用于计算对抗比赛(例如象棋对弈)中对手双方技能水 ...
- HDU 4870 Rating(概率、期望、推公式) && ZOJ 3415 Zhou Yu
其实zoj 3415不是应该叫Yu Zhou吗...碰到ZOJ 3415之后用了第二个参考网址的方法去求通项,然后这次碰到4870不会搞.参考了chanme的,然后重新把周瑜跟排名都反复推导(不是推倒 ...
- Elo rating system 模拟
package org.cc.foo_008; import java.util.ArrayList; import java.util.List; import java.util.Random; ...
- HDU4870 Rating(概率)
第一场多校,感觉自己都跳去看坑自己的题目里去了,很多自己可能会比较擅长一点的题目没看,然后写一下其中一道概率题的题解吧,感觉和自己前几天做的概率dp的思路是一样的.下面先来看题意:一个人有两个TC的账 ...
- HDU 4870 Rating 概率DP
Rating Time Limit:5000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Statu ...
- hdu 4870 Rating
题目链接:hdu 4870 这题应该算是概率 dp 吧,刚开始看了好几个博客都一头雾水,总有些细节理不清楚,后来看了 hdu 4870 Rating (概率dp) 这篇博客终于有如醍醐灌顶,就好像是第 ...
- HDU 4870 Rating(高斯消元 )
HDU 4870 Rating 这是前几天多校的题目,高了好久突然听旁边的大神推出来说是可以用高斯消元,一直喊着赶快敲模板,对于从来没有接触过高斯消元的我来说根本就是一头雾水,无赖之下这几天做DP ...
- 2014多校第一场J题 || HDU 4870 Rating(DP || 高斯消元)
题目链接 题意 :小女孩注册了两个比赛的帐号,初始分值都为0,每做一次比赛如果排名在前两百名,rating涨50,否则降100,告诉你她每次比赛在前两百名的概率p,如果她每次做题都用两个账号中分数低的 ...
随机推荐
- echarts 图表设置默认选中
echarts:https://echarts.apache.org/zh/api.html#events.legendselected tfjy1997:https://blog.csdn.net/ ...
- MySQL 时区与 serverTimezone
TL;DR 手动为 MySQL 指定非偏移量的时区,以避免 TIMESTAMP 类型夏令时问题和时区转化性能瓶颈 TIMESTAMP 范围:'1970-01-01 00:00:01' UTC to ' ...
- Lummmax 雷曼克斯 翔龙 X15 专业对讲机常用功能
Lummmax 雷曼克斯 翔龙 X15 专业对讲机常用功能 工作模式切换 ESC/M 在频率模式 (VFO) 与信道模式之间切换 编辑信道 在频率模式 (VFO) 下,输入目标频率并进行相关设置之后, ...
- OpenID Connect 验证
OpenID Connect Authentication 几乎所有的 Web 应用程序都提示用户创建账号并登录.为了创建账号,用户被要求提供他们的名字.电子邮件.口令.以及确认口令.不仅这些需要耗费 ...
- 中电金信发布两款大模型产品,打通AI+应用“最后一公里”
近年来,以大模型为代表的人工智能技术已成为引领新一代产业变革的核心动力.2024年政府工作报告首次提出"人工智能+",要求"大力推进现代化产业体系建设,加快发展新质生产力 ...
- Qt/C++地图坐标纠偏/地球坐标系/火星坐标系/百度坐标系/互相转换/离线函数
一.前言说明 为什么需要地球坐标纠偏这个功能,因为国家安全需要,不允许使用国际标准的地球坐标系,也并不是咱们这边这样,很多国家都是这样处理的,就是本国的地图经纬度坐标都是按照国家标准来的,所以就需要一 ...
- rysnc使用手册
rsync 是一个用于在本地和远程计算机之间同步文件和目录的命令行工具.它具有许多强大的功能,包括增量传输.压缩和保留权限等.以下是一些 rsync 的常用选项和用法示例: 基本用法 rsync [O ...
- [转][vue-router] Duplicate named routes definition动态路由addRoutes的踩坑
问题描述: 第一次进入页面,左侧静态路由和动态路由列表均能正常显示,但点击左侧其他路由后浏览器报警告[vue-router] Duplicate named routes definition-,并且 ...
- Web网页端IM产品RainbowChat-Web的v5.0版已发布
一.关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIM ...
- [rustGUI][iced]基于rust的GUI库iced(0.13)的部件学习(01):为窗口设置布局(column、row)
前言 本文是关于iced库的部件介绍,iced库是基于rust的GUI库,作者自述是受Elm启发. iced目前的版本是0.13.1,相较于此前的0.12版本,有较大改动. 本合集是基于新版本的关于分 ...