洛谷 P6775 - [NOI2020] 制作菜品(找性质+bitset 优化 dp)
好久没写过题解了,感觉几天没写手都生疏了
首先这种题目直接做肯定是有些困难的,不过注意到题目中有个奇奇怪怪的条件叫 \(m\ge n-2\),我们不妨从此入手解决这道题。
我们先来探究 \(m=n-1\) 的情况,观察大样例可知这种情况一定有解,我们不妨考虑这样一个贪心:假设 \(x\) 为使 \(d_i\) 取到最小值的 \(i\),\(y\) 为使得 \(d_i\) 取到最大值的 \(i\),那么我们就用 \(d_x\) 个原料 \(x\) 与 \(k-d_x\) 个原料 \(y\) 制作成一个菜品,这样会消耗掉一种菜品(\(x\)),重复 \(n-1\) 轮即可。
为什么这样贪心是对的?我们考虑一次操作,为了证明这次操作是合法的,我们需证明以下两个结论:
- \(d_x<k\)
- \(k-d_x\le d_y\),即 \(d_x+d_y\ge k\)。
这两个结论都可采用反证法证明。关于结论一,假设命题不成立,那么 \(d_x\ge k\),而由 \(d_x\) 的定义知 \(d_i\ge d_x\ge k\),故 \(\sum\limits_{i=1}^nd_i\ge nd_x\ge nk>mk\),矛盾。关于结论二,假设命题不成立,那么 \(d_y<k-d_x\),由 \(d_y\) 的定义知 \(d_i\le d_y<k-d_x\),故 \(\sum\limits_{i=1}^nd_i<(n-1)(k-d_x)+d_x=k+(n-2)(k-d_x)<k+(n-2)k=(n-1)k\),矛盾!
因此每次操作都是合法的。而显然每次操作之后都会有一个原料被消耗尽,因此我们就由 \(n\) 的情况过渡到了 \(n-1\) 的情况。又当 \(n=2\) 时有 \(d_1+d_2=k\),可以直接把两种原料搞在一起,符合条件。由数学归纳法可知这个贪心是没问题的。
接下来再考虑 \(m\ge n\) 的情况,我们考虑将 \(m\ge n\) 的情况向 \(m=n-1\) 的情况过渡,还是设 \(x\) 为使 \(d_i\) 取到最小值的 \(i\),\(y\) 为使得 \(d_i\) 取到最大值的 \(i\),这里有一个显然的结论,那就是 \(d_y\ge k\),否则 \(\sum\limits_{i=1}^nd_i<nk\le mk\),矛盾。因此我们只需每次选取 \(d_i\) 最大的 \(i\) 并消耗掉 \(k\) 克 \(i\) 原料,直到 \(m=n-1\) 为止即可。
最后考虑 \(m=n-2\) 的情况,再次观察样例可知这种情况就不一定有解了,那 \(m=n-2\) 的情况究竟什么时候有解,什么时候无解呢?
又到了考验选手观察能力的时候了,这里还有第四个结论,那就是 \(m=n-2\) 的情况有解当且仅当存在 \(S\subset\{1,2,3,\cdots,n\}\) 满足 \(\sum\limits_{x\in S}d_x=k(|S|-1)\)。
证明:充分性显然,记全集为 \(U=\{1,2,3,\cdots,n\}\),既然 \(S\) 满足 \(\sum\limits_{x\in S}d_x=k(|S|-1)\),那么 \(T=U-S\) 也一定满足 \(\sum\limits_{x\in T}d_x=k(|T|-1)\),因此我们只需对 \(S,T\) 分别执行 \(m=n-1\) 的操作即可。必要性:我们假设对于某个序列 \(d_1,d_2,\cdots,d_n\) 存在符合要求的解,我们考虑对于两个原料 \(i,j\),如果它们曾共同作为原料出现在这 \(n-2\) 个菜品中的某一个中,那么就连一条边 \((i,j)\),特别地如果一种原料单独做成一道菜品就连一条自环。显然这样会得到一张图 \(G=(V,E)\),并且 \(|V|=n,|E|\le n-2\),因此 \(G\) 不连通,而显然 \(G\) 中一定存在一个连通块是一棵树(否则假设所有联通块都存在环,那么边数必然 \(\ge n\))我们假设构成这个连通块的点集为 \(S\),这就是我们要找的集合 \(S\)。因此如果存在合法的方案,就必定存在符合要求的集合 \(S\)。
那么怎样找出这样的集合 \(S\) 呢?考虑对 \(\sum\limits_{x\in S}d_x=k(|S|-1)\) 进行变形,两边同时减去 \(k|S|\) 可得 \(-k|S|+\sum\limits_{x\in S}d_x=-k\),再将 \(-k\) 分配到求和号中可得 \(\sum\limits_{x\in S}d_x-k=-k\),这个长得一脸 01 背包的样子。我们考虑 \(dp_{i,j}\) 为当前考虑到前 \(i\) 个数,是否存在一个集合 \(S\) 使得 \(\sum_{x\in S}d_x-k=j\),按照就的 01 背包的套路即可,这样复杂度是 \(n^2k\) 的,可以拿到 \(85\) 分。不过发现 \(dp\) 数组每一个值的取值都只有 01 两种可能,故考虑 bitset 优化 \(dp\),具体来说我们对开一个 bitset<MAXN*MAXK*2+5> dp[MAXN+5],其中第 \(i\) 个 bitset 的第 \(j\) 位为 \(1\) 表示 \(dp_{i,j}=1\),否则表示 \(dp_{i,j}=0\)。对于形如 \(dp_{i,j}|=dp_{i-1,j-x}\) 的转移方程,我们就令 \(dp_i|=dp_{i-1}<<x\),显然二者是等价的,复杂度也就降到了 \(\dfrac{n^2k}{\omega}\)。
求完 bitset 之后检验 \(dp_{n,-k}\) 是否等于 \(1\),如果 \(dp_{n,-k}=0\) 则无解,否则按照输出路径的套路找出符合要求的集合 \(S\),然后用 \(m=n-1\) 的算法输出方案即可。
u1s1 bitset yyds!
const int MAXN=500;
const int MAXK=5e3;
int n,m,k,a[MAXN+5];
void work(vector<pii> vx,int n,int m){
set<pii> st;
for(int i=0;i<vx.size();i++) st.insert(vx[i]);
for(int i=1;i<=m;i++){
if(m>=n){
pii pp=*st.rbegin();st.erase(st.find(pp));
printf("%d %d\n",pp.se,k);--m;st.insert(mp(pp.fi-k,pp.se));
} else {
pii p1=*st.begin();st.erase(st.find(p1));
pii pn=*st.rbegin();st.erase(st.find(pn));
printf("%d %d %d %d\n",p1.se,p1.fi,pn.se,k-p1.fi);
st.insert(mp(pn.fi-(k-p1.fi),pn.se));
}
}
}
bitset<MAXN*MAXK*2+5> dp[MAXN+5];
void clear(){
for(int i=0;i<=n;i++) dp[i].reset();
}
vector<pii> v1,v2;
void findpath(int x,int v){
if(!x) return;
if(dp[x-1][v]){
v1.pb(mp(a[x],x));
findpath(x-1,v);
} else {
v2.pb(mp(a[x],x));
findpath(x-1,v-(a[x]-k));
}
}
void solve(){//remember to make it first
scanf("%d%d%d",&n,&m,&k);clear();
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
if(m>=n-1){
vector<pii> v;
for(int i=1;i<=n;i++) v.pb(mp(a[i],i));
work(v,n,m);return;
} int delta=n*k;dp[0][delta]=1;
for(int i=1;i<=n;i++){
int t=a[i]-k;
if(t>=0) dp[i]=dp[i-1]|(dp[i-1]<<t);
else dp[i]=dp[i-1]|(dp[i-1]>>(-t));
}
if(!dp[n][delta-k]){puts("-1");return;}
v1.clear();v2.clear();findpath(n,delta-k);
// for(int i=0;i<v1.size();i++) printf("%d ",v1[i].se);printf("\n");
// for(int i=0;i<v2.size();i++) printf("%d ",v2[i].se);printf("\n");
work(v1,v1.size(),v1.size()-1);
work(v2,v2.size(),v2.size()-1);
}
int main(){
int qu;scanf("%d",&qu);
for(int i=1;i<=qu;i++) solve();
return 0;
}
洛谷 P6775 - [NOI2020] 制作菜品(找性质+bitset 优化 dp)的更多相关文章
- 洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP
洛谷P2216 )逼着自己写DP 题意: 给定一个带有数字的矩阵,找出一个大小为n*n的矩阵,这个矩阵中最大值减最小值最小. 思路: 先处理出每一行每个格子到前面n个格子中的最大值和最小值.然后对每一 ...
- BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】
题目链接 洛谷P1912[原题,需输出方案] BZOJ1563[无SPJ,只需输出结果] 题解 四边形不等式 什么是四边形不等式? 一个定义域在整数上的函数\(val(i,j)\),满足对\(\for ...
- 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)
点此看题面 大致题意: 你可以对一个序列进行\(k\)次分割,每次得分为两个块元素和的乘积,求总得分的最大值. 区间\(DPor\)斜率优化\(DP\) 这题目第一眼看上去感觉很明显是区间\(DP\) ...
- 洛谷P2569 (BZOJ1855)[SCOI2010]股票交易 【单调队列优化DP】
Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...
- 洛谷 P2254 [NOI2005]瑰丽华尔兹(单调栈优化DP)
题目描述 不妨认为舞厅是一个N行M列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地.钢琴可以在空地上滑动,但不能撞上家具或滑出舞厅,否则会损坏钢琴和家具,引来难缠的船长.每个时刻,钢琴都会随 ...
- 洛谷2900 [USACO08MAR]土地征用Land Acquisition (斜率优化+dp)
自闭的一批....为什么斜率优化能这么自闭. 首先看到这个题的第一想法一定是按照一个维度进行排序. 那我们不妨直接按照\(h_i\)排序. 我们令\(dp[i]\)表示到了第\(i\)个矩形的答案是多 ...
- 洛谷3195 [HNOI2008]玩具装箱TOY(斜率优化+dp)
qwq斜率优化好题 第一步还是考虑最朴素的\(dp\) \[dp=dp[j]+(i-j-1+sum[i]-sum[j])^2 \] 设\(f[i]=sum[i]+i\) 那么考虑将上述柿子变成$$dp ...
- 洛谷 P6776 - [NOI2020] 超现实树(找性质,神仙题)
洛谷题面传送门 nb tea 一道! 首先考虑怎样入手分析这个看似非常不可做的问题.首先题目涉及高度无穷的树,根本枚举不了.不过我们冷静一下就会发现,如果我们记 \(mx=\max\limits_{i ...
- 【洛谷 5002】专心OI - 找祖先 (树上计数)
专心OI - 找祖先 题目背景 \(Imakf\)是一个小蒟蒻,他最近刚学了\(LCA\),他在手机\(APP\)里看到一个游戏也叫做\(LCA\)就下载了下来. 题目描述 这个游戏会给出你一棵树,这 ...
随机推荐
- JAVA String、StringBuffer、StringBuilder类解读
JAVA String.StringBuffer.StringBuilder类解读 字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作 ...
- Egg.js学习与实战系列 · 文件上传配置
在使用Egg.js搭建文件上传服务时,遇到了几个一般新手都会遇到的坑. 经查阅官方文档,Egg框架中默认使用egg-multipart插件进行文件上传,所以上传文件前需要做相关的配置. 上传文件提示: ...
- 第2次 Beta Scrum Meeting
本次会议为Beta阶段第2次Scrum Meeting会议 会议概要 会议时间:2021年5月31日 会议地点:「腾讯会议」线上进行 会议时长:0.5小时 会议内容简介:对完成工作进行阶段性汇报:对下 ...
- 热身 for computer industry
项目 内容 作业属于 班级博客 作业要求 作业要求 个人课程目标 掌握软件工程基础知识 具体有助方面 个人认知与规划 其他参考文献 博客Ⅰ 博客 Ⅱ 选择计算机 你为什么选择计算机专业?你认为你的条件 ...
- 设计的MOS管三极管简单开关电路驱动能力不够3
16楼说得非常明白,补充一点,R3如果不要,会有下冲产生.4 Q: Z/ G G1 s8 Z- } 能解释下为什么会产生过冲吗?9 i, P* D* X) u. t/ b ^ 让我们这些菜鸟学习学 ...
- FreeRTOS学习笔记——FreeRTOS 任务基础知识
RTOS 系统的核心就是任务管理,FreeRTOS 也不例外,而且大多数学习RTOS 系统的工程师或者学生主要就是为了使用RTOS 的多任务处理功能,初步上手RTOS 系统首先必须掌握的也是任务的创建 ...
- 转:Modelsim和Vcs+Verdi使用技巧(Linux)
Modelsim脚本自动仿真 1.创建文件 run.do,"#"为注释符号 quit -sim #退出上次仿真 .main clear #清除上次仿真所有文件以及打印信息 vlib ...
- 设计模式学习-使用go实现单例模式
单例模式 定义 优点 缺点 适用范围 代码实现 懒汉模式 饿汉模式 双重检测 sync.Once 参考 单例模式 定义 什么是单例模式:保证一个类仅有一个实例,并提供一个全局访问它的全局访问点. 例如 ...
- TTMS 一个基于Java Swing的Socket通信的剧院票务管理系统
TTMS (Theater Ticket Management System) 点我进入github TTMS全称剧院票务管理系统,分为客户端和服务器端.服务器端可以接收客户端连接请求,客户端相当于我 ...
- webpack 配置devServer 服务器
webpack 配置devServer 服务器 /** * loader: 1. 下载 2. 使用(配置) * plugins:1. 下载 2. 引入 3.使用 */ // 用来拼接绝对路径的方法 c ...