题面传送门

好久没写过题解了,感觉几天没写手都生疏了

首先这种题目直接做肯定是有些困难的,不过注意到题目中有个奇奇怪怪的条件叫 \(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)的更多相关文章

  1. 洛谷P2216: [HAOI2007]理想的正方形 单调队列优化DP

    洛谷P2216 )逼着自己写DP 题意: 给定一个带有数字的矩阵,找出一个大小为n*n的矩阵,这个矩阵中最大值减最小值最小. 思路: 先处理出每一行每个格子到前面n个格子中的最大值和最小值.然后对每一 ...

  2. BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】

    题目链接 洛谷P1912[原题,需输出方案] BZOJ1563[无SPJ,只需输出结果] 题解 四边形不等式 什么是四边形不等式? 一个定义域在整数上的函数\(val(i,j)\),满足对\(\for ...

  3. 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)

    点此看题面 大致题意: 你可以对一个序列进行\(k\)次分割,每次得分为两个块元素和的乘积,求总得分的最大值. 区间\(DPor\)斜率优化\(DP\) 这题目第一眼看上去感觉很明显是区间\(DP\) ...

  4. 洛谷P2569 (BZOJ1855)[SCOI2010]股票交易 【单调队列优化DP】

    Description 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价 ...

  5. 洛谷 P2254 [NOI2005]瑰丽华尔兹(单调栈优化DP)

    题目描述 不妨认为舞厅是一个N行M列的矩阵,矩阵中的某些方格上堆放了一些家具,其他的则是空地.钢琴可以在空地上滑动,但不能撞上家具或滑出舞厅,否则会损坏钢琴和家具,引来难缠的船长.每个时刻,钢琴都会随 ...

  6. 洛谷2900 [USACO08MAR]土地征用Land Acquisition (斜率优化+dp)

    自闭的一批....为什么斜率优化能这么自闭. 首先看到这个题的第一想法一定是按照一个维度进行排序. 那我们不妨直接按照\(h_i\)排序. 我们令\(dp[i]\)表示到了第\(i\)个矩形的答案是多 ...

  7. 洛谷3195 [HNOI2008]玩具装箱TOY(斜率优化+dp)

    qwq斜率优化好题 第一步还是考虑最朴素的\(dp\) \[dp=dp[j]+(i-j-1+sum[i]-sum[j])^2 \] 设\(f[i]=sum[i]+i\) 那么考虑将上述柿子变成$$dp ...

  8. 洛谷 P6776 - [NOI2020] 超现实树(找性质,神仙题)

    洛谷题面传送门 nb tea 一道! 首先考虑怎样入手分析这个看似非常不可做的问题.首先题目涉及高度无穷的树,根本枚举不了.不过我们冷静一下就会发现,如果我们记 \(mx=\max\limits_{i ...

  9. 【洛谷 5002】专心OI - 找祖先 (树上计数)

    专心OI - 找祖先 题目背景 \(Imakf\)是一个小蒟蒻,他最近刚学了\(LCA\),他在手机\(APP\)里看到一个游戏也叫做\(LCA\)就下载了下来. 题目描述 这个游戏会给出你一棵树,这 ...

随机推荐

  1. javascript-jquery对象的动画处理

    一.显示与隐藏动画效果 1.hide(动画持续时间,easing用来指定切换效果,动画执行完毕调用函数): $("p").hide(5000,"swing",f ...

  2. Java继承中父类和子类构造函数的问题

    父类有无参构造函数时(显示或隐式),子类的有参和无参构造函数都是默认调用父类的无参构造函数:当父类只有有参构造函数时,子类可以有有参和无参构造函数,子类有参构造函数必须显式调用父类的有参构造函数,子类 ...

  3. [对对子队]会议记录4.13(Scrum Meeting 4)

    今天已完成的工作 梁河览 ​ 工作内容:初步完成存档功能 ​ 相关issue:实现游戏内UI界面使用的组件 马嘉 ​ 工作内容:找到了原料组件 ​ 相关issue:实现游戏内UI界面使用的组件 吴昭邦 ...

  4. 2021.7.17 NKOJ周赛总结

    发现自己简直是个智障:T1模数写成1e9+9:T2居然没有考虑刚好一个周期的情况:T4用"%lld"读入"unsigned long long".~qwq~ T ...

  5. 攻防世界 杂项 7.Aesop_secret

    打开发现是个gif,以为有个二维码扫一下就给flag,结果被欺骗.呜呜呜 好了,还是使用编辑器看一下吧 发现了好玩的,U2FsdGVkX19QwGkcgD0fTjZxgijRzQOGbCWALh4sR ...

  6. Python NameError:name ‘xrange’ is not defined

    在python3 中会出这个问题,而xrange( )函数时在python 2.x中的一个函数,在Python 3中,range()的实现方式与xrange()函数相同,所以就不存在专用的xrange ...

  7. Serverless 工程实践|自建 Apache OpenWhisk 平台

    作者 | 刘宇(江昱) 前言:OpenWhisk 是一个开源.无服务器的云平台,可以在运行时容器中通过执行扩展的代码响应各种事件,而无须用户关心相关的基础设施架构. OpenWhisk 简介 Open ...

  8. Spring事务的介绍,以及基于注解@Transactional的声明式事务

    前言 事务是一个非常重要的知识点,前面的文章已经有介绍了关于SpringAOP代理的实现过程:事务管理也是AOP的一个重要的功能. 事务的基本介绍 数据库事务特性: 原子性 一致性 隔离性 持久性 事 ...

  9. ffmpeg第7篇:数据流选择神器-map指令

    自动选择规则 ffmpeg在处理视频时,如果只提供了输入和输出参数,ffmpeg会自动地去选择相应的视频流和音频流来合成文件 自动选择的方式根据如下规则: 视频流:选分辨率最高的,比如有两个视频,一个 ...

  10. Git 图形化客户端--Sourcetree

    1.图形化客户端: sourcetre下载:https://www.sourcetreeapp.com/ 2.接着并执行SourceTreeSetup-3.1.3.exe,会进入登录或注册bitbuc ...