首页 > 其他分享 >CF1993D-二分+dp处理中位数

CF1993D-二分+dp处理中位数

时间:2024-08-05 15:30:21浏览次数:8  
标签:二分 val int 中位数 数组 CF1993D dp

CF1993D-二分+dp处理中位数

大致题意

给定两个正整数 n 和 k 以及另一个由 n 个整数组成的数组 a 。

在一次操作中,可以选择 a 的任意一个大小为 k 的子数组,然后将其从数组中删除,而不改变其他元素的顺序。更正式地说,假设$ (l,r) $是对子数组 \(a_l,a_{l+1},…,a_r\) 的操作,使得 \(r−l+1=k\) ,那么执行此操作意味着将 a 替换为 $[a_1,…,a_{l−1},a_{r+1},…,a_n ] $。

例如,如果 $a=[1,2,3,4,5] $,我们对这个数组执行 \((3,5)\) 操作,它就会变成 \(a=[1,2]\) 。此外,操作 \((2,4)\) 的结果是 \(a=[1,5]\) ,操作 \((1,3)\) 的结果是 \(a=[4,5]\) 。

当 a 的长度大于 k (即 $|a| > k $)时,你必须重复操作。处理后,数组 a 中所有剩余元素的最大可能中值是多少?

  • 对长度为 n 的数组中的元素按非递减顺序排序后,中位数是索引为$ ⌊(n+1)/2⌋$ 的元素。例如 $median([2,1,5,4,3])=3 \(、\) median([5])=5 和 median([6,8,2,4])=4 $。

解题思路

我们可以通过二分答案+dp的形式来解决这个问题

通过二分中位数p,每次通过dp检查是否能够满足当前的中位数,在处理中位数一类的题目中非常常见

我们重点讨论dp的过程:

我们在处理中位数类型的dp时常见的操作是将数值\(a_i\)根据其与中位数\(mid\)的关系,分别处理为\(+1(a_i>mid)或者-1(a_i<mid)\),对其求前缀和,若\(f[n]>0\)表示当前中位数可以实现

再结合本题,本题考虑删除长度为k的子序列,通过观察我们可以发现我们需要将整个序列按照长度k划分,例如序列\(a=[1,2,3,4,5,6]\),如果k==2我们可以将其划分为\([1,2][3,4][5,6]\),每一段的第一个元素(\((i-1) \% k == 0\))我们要特殊考虑

  • 若\((i-1)\%k==0\),那么考虑两种情况:
    • 作为一个最终结果的开始 \(f[i] = val\)
    • 前k个被删除,作为上上个段的一部分\(f[i] = f[i-k]\)
  • 否则也考虑两种情况:
    • 继续作为上一个段的一部分:\(f[i] = f[i-1]+val\)
    • 前k个被删除,作为上上个段的一部分:\(f[i] = f[i-k]\)

代码实现

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
void solve()
{
	int n,k;
	cin>>n>>k;
	vector<int> a(n+1);
	for(int i = 1;i <= n;++i) cin>>a[i];
	auto check = [&](int mid)
	{
		vector<int> f(n+1,-1e9);
		f[0] = 0;
		for(int i = 1;i<= n;++i)
		{
			int val = (a[i]>=mid?1:-1);
			if((i-1)%k==0)
			{
				if(i-k>=0)
					f[i] = max(f[i-k],val);
				else
					f[i] = val;
			} 
			else{
				if(i-k>=0) f[i] = max(f[i-1]+val,f[i-k]);
				else f[i] = f[i-1]+val;
			}
		}
		return f[n]>0;
	};
	int l = 1,r = 1e9+7;
	while(l<r)
	{
		int mid = (l+r+1)/2;
		if(check(mid)) l=mid;
		else r = mid-1;
	} 
	int ans = r;
	cout<<ans<<endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int tt;
	cin>>tt;
	while(tt--)solve();
	return 0;
} 

标签:二分,val,int,中位数,数组,CF1993D,dp
From: https://www.cnblogs.com/empty-y/p/18342982

相关文章

  • 动态规划之——背包DP(入门篇)
    文章目录概要说明01背包模板例题题意概要思路code1code201背包的应用题题目来源思路code完全背包模板例题题意概要思路code概要说明本文只讲了01背包和完全背包,至于其他背包问题后续补充01背包模板例题点击这里题意概要思路01背包的模板题首先对于背包问......
  • 换根 dp
    板子P2986[USACO10MAR]GreatCowGatheringGP3478[POI2008]STA-StationP3047[USACO12FEB]NearbyCowsG很好的一题f[i][j]表示与点i(向下(点i儿子1中的点))距离为j的点的权值和g[i][j]表示与点i(所有)距离为j的点的权值和需要特别注意的是刚开始时g[i][j]=......
  • 状态压缩DP
    状态压缩DP定义:‌状态压缩是一种使用二进制数来表示状态的方法,通常用于表示只有两种状态(0和1)的对象。Acwing,291蒙特里安的梦想291.蒙德里安的梦想-AcWing题库题目概览求把N×......
  • 常见CMS漏洞(WordPress、DeDeCMS、ASPCMS、PHPMyadmin、Pageadmin)
    目录一:WordPress步骤一:进入Vulhub靶场并执行以下命令开启靶场;在浏览器中访问并安装好子...步骤二:思路是修改其WP的模板写入一句话木马后门并访问其文件即可GetShel;登陆WP后点击【外观】--》【编辑】--》404.php步骤三:访问以下连接即可获取WebShel...姿势二:上传主......
  • Luogu P1777 帮助 题解 [ 紫 ] [ 线性 dp ] [ 状压 dp ]
    帮助:大毒瘤!!!调了我2h,拍了我2h,最后没调出来,重写才AC。wdnmd。思路这题主要是线性dp,而状压dp只是最后在统计答案时的一个辅助。首先定义\(dp[i][j][k]\)为考虑前\(i\)本书,已经抽出来了\(j\)本,最后没被抽出来的一本书是高度\(k\)的最小混乱度。每次放入的书与最后一位......
  • 简析传输层协议——TCP、UDP协议
    TCP/IP协议族的传输层协议TCP(TransmissionControlProtocol)传输控制协议UDP(UserDatagramProtocol)用户数据报协议TCP协议介绍:TCP是面向连接的、可靠的进程到进程通信的协议TCP提供全双工服务,即数据可在同一时间双向传输TCP报文段:TCP将若干个字节构成一个分......
  • DP
    1)数位DP数位DP:用来解决一类特定问题,这种问题比较好辨认,一般具有这几个特征:要求统计满足一定条件的数的数量(即,最终目的为计数);这些条件经过转化后可以使用「数位」的思想去理解和判断;输入会提供一个数字区间(有时也只提供上界)来作为统计的限制;上界很大(比如10^{18}),暴力枚举......
  • centos7上dpdk绑定vfio-pci失败
    记一次使用dpdk中的报错:运行dpdk/usertools/dpdk-devbind.py-bvfio-pci02:05.0来绑定设备到vfio-pci时,报出了如下错误:Error:bindfailedfor0000:02:05.0-Cannotbindtodrivervfio-pci:[Errno19]NosuchdeviceError:unbindfailedfor0000:02:05.0-Cannot......
  • Luogu P5005 中国象棋 - 摆上马 / Luogu P8756 国际象棋 题解 [ 蓝 ] [ 状压 dp ] [
    国际象棋:模板棋盘状压。摆上马:需要点思维的棋盘状压,相比上一道题加了“蹩马脚”的设定。Easy_version:国际象棋概述一下此类棋盘问题的思路:用二进制数表示出棋盘上某一行的状态。用位运算预处理出合法的单行状态,以及需要用到的一些东西。用位运算判断前一行或者前几行能否......
  • Debian系包管理工具dpkg,apt-get,apt的区别
    解密Linux包管理:apt和apt-get的区别-系统极客(sysgeek.cn)dpkg:幕后英雄dpkg是Debian包管理系统的核心,是一个底层工具,用于直接操作.deb文件。你可以把它想象成一个搬运工,负责把软件包里的「内容」搬到电脑里。但是,它不处理依赖关系,这项工作交由apt或apt-get来完成。ap......