CF521D Shop 贪心
题意:
\(n\)个数,有\(m\)个操作,形如:
1,将\(x_i\)改成\(val_i\)
2,将\(x_i\)加上\(val_i\)
3,将\(x_i\)乘上\(val_i\)
其中第\(i\)个操作的编号为\(i\). 现在你可以从中选择最多\(k\)个操作(不能重复选),并按一定顺序执行,使得\(\prod_{i = 1}^{n}x_i\)最大。
第一行输出选择的操作个数,第二行按执行顺序输出方案。
题解:
如果只有3号操作,那么因为最后的答案是乘起来,而不是加起来,因此每个乘,不管对哪个数进行操作,对ans的贡献都是相同的。所以我们可以直接按操作的值排序,贪心的取值即可。
但现在有3种操作,我们可以考虑将其转换为3号操作。
首先我们有个比较显而易见的结论:对于已经选定的\(k\)个操作,我们一定是先赋值,再加,再乘,即按123的操作依次进行。
我们先考虑是否可以将加法变为乘法。
基于贪心的思想,对于同一个数,我们选择加法操作,肯定是先选加得多的,因此我们将加法从高到底排序,依次操作。
那么每个加法的使用前提都是前一个加法已经被使用过了。
因此对于每个加法,它的使用前提都是固定的,即对于每个加法操作,都是把某个值为\(x\)的数变为一个值为\(y\)的数,其中\(x\)是这个数经过它前面的所有加法后变成的数,也就是一段前缀和。
因为每个加法使用的条件都是固定的,因此我们可以把任意一个加法看成一个\(val\)为\(\frac{x}{y}\)的乘法,于是我们就可以按照上面的方法进行贪心了。
那么如何保证这样一定合法呢?
可以知道,这样合法,当且仅当我们取的每段加法都是一段前缀,可以证明,排在后面的加法,转化为乘法后肯定也没有之前优,因此如果我们取了一个加法,那么这个加法之前的加法肯定也都取过了。
一个简单的证明:
设\(a > b > c > d\),试证明前面的乘法肯定要比后面的大,即证:
\]
\]
显然成立。
又因为乘法是没有先后顺序的,因此不管我们取的加法是不是断断续续取的,反正我们可以把它调整到正确的顺序。
那么现在来考虑操作1.
首先对于任意一个数而言,最多只会进行一次操作一(因为进行多次就相当于之前的操作都无效了)。
那么我们先去掉较劣的操作1,对于每个数都只保留最大的那个(如果有的话)
可以观察到,初步筛选后,操作1实际上就相当于把原数加上一个值变为了\(val_i\),因此我们可以以这个增量为新的\(val_i\),把这个操作转换为加法,然后当做一个普通的加法放到操作2的数组当中去sort。
这样看上去打破了我们之前按123依次进行的约定?
其实并没有,考虑2种情况。
1,我们在取值时没有取到这个赋值操作。那么显然不会产生影响
2,我们在取值时取到了这个赋值操作,那么因为乘法可以打乱顺序,因此我们依然可以看做是在最开始进行了这个赋值操作,那么这个操作确实可以起到加上一个值的效果,并不会违背我们之前推出的性质。
简单来说,做这道题的时候注意一下几点:
1,将3个操作都转换为乘法
2,运用贪心的原则
3,记住乘法是可以随意调整顺序的。
4,因为最后求的是乘积,所以每个乘法对答案的贡献都是相同的。
其中第3点非常重要,这题所有操作的正确性(包括贪心和转换部分)都是基于这个性质的!
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 101000
#define LL long long
int n, m, k, tot1, tot2, tot3, cnt;
LL s[AC];
struct node{
int opt, id, x;LL v, w;//w为分母
}m1[AC], m2[AC], m3[AC], ans[AC];//不需要知道具体值……所以减1再比较也不影响结果,知道哪些是我要的操作就好了
inline bool cmp1(node a, node b){return (a.x != b.x) ? (a.x < b.x) : (a.v < b.v);}//给操作1去重
inline bool cmp2(node a, node b){return (a.x != b.x) ? (a.x < b.x) : (a.v > b.v);}//上面去重所以从小到大,这里贪心所以从大到小
inline bool cmp3(node a, node b){return a.opt < b.opt;}//先1再2再3,且取走的加法是一段前缀才能保证结果正确性
inline bool cmp4(node a, node b){return a.v * b.w > a.w * b.v;}//分数比较
inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}
void pre()
{
n = read(), m = read(), k = read();
for(R i = 1; i <= n; i ++) s[i] = read();
for(R i = 1; i <= m; i ++)
{
int a = read(), b = read(), c = read();
if(a == 1 && c > s[b]) m1[++ tot1] = (node){1, i, b, c, 1};//如果改了反而不优就算了
else if(a == 2) m2[++ tot2] = (node){2, i, b, c, 1};
else if(a == 3) m3[++ tot3] = (node){3, i, b, c, 1};//默认分母为1
}
}
void build()
{
sort(m1 + 1, m1 + tot1 + 1, cmp1);
int tmp = 0;
for(R i = 1; i <= tot1; i ++)
if(m1[i].x != m1[i + 1].x) m1[++ tmp] = m1[i];//对于同一个数的赋值操作只保留最大的,否则影响贪心正确性
tot1 = tmp;
for(R i = 1; i <= tot1; i ++)
m1[i].v = m1[i].v - s[m1[i].x], m2[++ tot2] = m1[i];//把赋值变成加法后加入m2中
sort(m2 + 1, m2 + tot2 + 1, cmp2);//因为要每个数单独看,所以还是要先按数排序,再按大小排序
LL sum = 0;
for(R i = 1; i <= tot2; i ++)
{
if(m2[i].x != m2[i - 1].x) sum = s[m2[i].x];//对于新的一段就重置一下
m2[i].w = sum, sum += m2[i].v;//v不用修改,因为统一-1了,所以分子要-sum
}
for(R i = 1; i <= tot3; i ++) m3[i].v --;//统一-1不会影响比较结果
for(R i = 1; i <= tot2; i ++) m3[++ tot3] = m2[i];
}
void work()
{
sort(m3 + 1, m3 + tot3 + 1, cmp4);
int tmp = min(tot3, k);
for(R i = 1; i <= tmp; i ++) ans[++ cnt] = m3[i];
printf("%d\n", cnt);
sort(ans + 1, ans + cnt + 1, cmp3);
for(R i = 1; i <= cnt; i ++) printf("%d ", ans[i].id);
printf("\n");
}
int main()
{
//freopen("in.in", "r", stdin);
pre();
build();
work();
// fclose(stdin);
return 0;
}
CF521D Shop 贪心的更多相关文章
- [CF521D]Shop
[CF521D]Shop 题目大意: 你有一个长度为\(k(k\le10^5)\)的数列\(A_{1\sim k}\),有\(n(n\le10^5)\)种操作,操作包含以下\(3\)种: 将\(A_x ...
- 「CF521D」 Shop
「CF521D」 Shop 传送门 题目说是有三种操作,首先可以知道赋值操作是可以转化为加法操作的,即 \((1,b) \rightarrow (2,b-a_i)\) 然后加法对于一个数你肯定优先选择 ...
- CF F. Shovels Shop(前缀和预处理+贪心+dp)
F. Shovels Shop time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...
- 「CF521D」Shop
传送门 Luogu 解题思路 当只有第三类操作时,我们显然先进行val较大的操作,这是显然的. 那么就考虑把所有的操作都转变为第三类操作. 第一类操作,显然很容易变为第二类操作:单点维护最大的最终结果 ...
- Codeforces 521D - Shop(贪心)
Codeforces 题目传送门 & 洛谷题目传送门 一道不算太难的贪心,可惜又没自己想出来,显然省选之后我的能力呈 \(y=-1145141919810192608179998244353x ...
- Codeforces Round #552 (Div. 3) F. Shovels Shop (前缀和预处理+贪心+dp)
题目:http://codeforces.com/contest/1154/problem/F 题意:给你n个商品,然后还有m个特价活动,你买满x件就把你当前的x件中最便宜的y件价格免费,问你买k件花 ...
- Codeforces Gym 100803C Shopping 贪心
Shopping 题目连接: http://codeforces.com/gym/100803/attachments Description Your friend will enjoy shopp ...
- codeforces 286 E. Ladies' Shop (FFT)
E. Ladies' Shop time limit per test 8 seconds memory limit per test 256 megabytes input standard inp ...
- hdu 3573(数学+贪心)
Buy Sticks Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
随机推荐
- Java 分割、合并byte数组
场景:上传文件较大,把存放文件内容byte数组拆分成小的.下载的时候按照顺序合并. 起初觉得挺麻烦的,写完觉得挺简单. 切割: /** * 拆分byte数组 * * @param bytes * 要拆 ...
- PHPCMS V9 的手机门户wap绑定单页面
当前的Phpcms V9手机网站的设置还有点弱,绑定的栏目不能设置选择模板,而且不能绑定单页面page.不过可以自定义做到绑定单页面page这一个功能:1.修改phpcms\modules\wap\i ...
- sqoop安装与简单实用
一,sqoop安装 1.解压源码包 2.配置环境变量 3.在bin目录下的 /bin/configsqoop 注释掉check报错信息 4.配置conf目录下 /conf/sqoop-env.sh 配 ...
- kNN--近邻算法
kNN--近邻算法 kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性. 在机器学习中常用于分类. 数学内容: ...
- US Customs bond DDP 船运
客户提供目的港门点地址,提供美国进口产品的关税税率基本上就可以了关于ISF信息到时候你发给老外让老外填填好就可以了BAND 货值*0.575%POA 货值*0.335%这二个费用如果国内付就付了,国 ...
- 城联数据TSM技术方案起底
近日,城联数据有限公司与中国电信签订了<基于NFC技术的公交业务的合作协议>.双方基于NFC技术开展互联互通城市公交卡业务合作,实现符合住房和城乡建设部城市公用事业互联互通卡系列标准的移动 ...
- Thunder团队Final周贡献分分配结果
小组名称:Thunder 项目名称:爱阅app 组长:王航 成员:李传康.翟宇豪.邹双黛.苗威.宋雨.胡佑蓉.杨梓瑞 分配规则 则1:基础分,拿出总分的20%(8分)进行均分,剩下的80%(32分)用 ...
- MySort试验记录
MySort试验记录 编写目标 结果代码 思路 将数组每一个项目的第三组数字抽出来并且排序成12345的顺序,并形成新数组k3. 把原数组的每一项与k3进行比较,每符合一项便输出一项,从而重新排序出新 ...
- OGNL动态实现result
OGNL就是struts.xml文件中的<result>通过get()方法,动态获取action类中的变量 <struts> <package name="de ...
- 遇到Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so问题的解决方法
运行一个基于tensorflow的模型时,遇到Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so问题. 解决方法:打开 ...