沙雕贪心......

我一开始想的是倒着来,每次减去一个。

然后我们就有两个决策:去掉最后一个/去掉前面某一个。

然后第一个决策用并查集维护,第二个决策用线段树即可。仔细想想觉得普及组不会考这种东西,慌得一批。

然后又发现可能有问题:你可能取x个的时候不从x + 1转移过来,而是x + 2

然后就不会了。

然后看提解发现正解是顺着来......什么沙雕。

结论:若取x个的时候最优解是集合S,那么取x+1个时的最优解集合一定包含S。(说明了上面我的做法是对的)

证:

即证对于每一个取x+1的方案p,若不包含S,都可以找到一个包含S的方案比它更优。

设取x个的最优方案为r

考虑最右那一个:

①p的最后那个等于r的最右那一个时,前面我们随便去掉一个不与r配对的位置d,然后p一定还与r不同。

我们把p调整成r,然后加上d,这样就比原来的p更优了。

②p的最后那个小于r的最后那一个时,我们同样去掉一个d,然后调整,最后加上d,就会更优。

③p的最后那个大于r的最后那个时,把p的最后那个去掉,同时p的价值减去(2 * 从r最后到p最后的距离)。

这样就相当于情况①中去掉d之后的p了。

然后调整成r之后把原来p的最后加上,再加上减去的价值,就会比原来的p更优。

 #include <cstdio>
#include <algorithm>
#include <queue> const int N = ; int a[N], x[N], g[N];
std::priority_queue<int> Q; int main() {
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &x[i]);
x[i] <<= ;
}
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
} for(int i = n; i >= ; i--) {
if(x[i] + a[i] > x[g[i + ]] + a[g[i + ]]) {
g[i] = i;
}
else {
g[i] = g[i + ];
}
} int now = g[]; int ans = a[now] + x[now], pos = ;
printf("%d\n", ans); for(int i = ; i <= n; i++) {
while(pos < now) {
Q.push(a[pos]);
pos++;
}
if(pos == now) {
pos++;
}
if(!Q.empty() && Q.top() > a[g[now + ]] + x[g[now + ]] - x[now]) {
ans += Q.top();
Q.pop();
}
else {
ans -= x[now];
now = g[now + ];
ans += a[now] + x[now];
}
printf("%d\n", ans);
} return ;
}

AC代码

然后我又打了一开始那个线段树的想法......

 #include <cstdio>
#include <algorithm>
#include <queue> const int N = , INF = 0x3f3f3f3f; int a[N], x[N], ans[N];
int small[N << ], fa[N]; int find(int x) {
if(fa[x] == x) {
return x;
}
return fa[x] = find(fa[x]);
} inline void pushup(int o) {
int ls = o << ;
int rs = ls | ;
if(a[small[ls]] <= a[small[rs]]) {
small[o] = small[ls];
}
else {
small[o] = small[rs];
}
return;
} void build(int l, int r, int o) {
if(l == r) {
small[o] = r;
return;
}
int mid = (l + r) >> ;
build(l, mid, o << );
build(mid + , r, o << | );
pushup(o);
return;
} int ask(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) {
return small[o];
}
int mid = (l + r) >> ; if(R <= mid) {
return ask(L, R, l, mid, o << );
}
if(mid < L) {
return ask(L, R, mid + , r, o << | );
} int as = ask(L, R, l, mid, o << );
int t = ask(L, R, mid + , r, o << | );
if(a[t] < a[as]) {
as = t;
}
return as;
} void change(int p, int l, int r, int o) {
if(l == r) {
a[r] = INF;
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
change(p, l, mid, o << );
}
else {
change(p, mid + , r, o << | );
}
pushup(o);
return;
} int main() {
int n, sum = ;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &x[i]);
x[i] <<= ;
}
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
fa[i] = i;
sum += a[i];
}
sum += x[n];
ans[n] = sum; build(, n, ); int now = n;
for(int i = n - ; i >= ; i--) {
int pos = ask(, now - , , n, );
if(a[now] + x[now] - x[find(now - )] > a[pos]) {
sum -= a[pos];
change(pos, , n, );
fa[pos] = find(pos - );
}
else {
sum -= (a[now] + x[now] - x[find(now - )]);
now = find(now - );
}
ans[i] = sum;
} for(int i = ; i <= n; i++) {
printf("%d\n", ans[i]);
}
return ;
}

AC代码

话说这个代码我调都没调,一次就写对了。

洛谷P2672 推销员的更多相关文章

  1. 洛谷 P2672 推销员 解题报告

    P2672 推销员 题目描述 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户.螺丝街一共有N家住户,第i家住户到入口的距离为 ...

  2. 洛谷P2672 推销员 题解 贪心

    题目链接:https://www.luogu.org/problem/P2672 这道题目是贪心,贪心的思想是: 选择 \(m\) 户人家的最大疲劳值应该是以下两种方案中的较大值: 方案一:选择 \( ...

  3. 洛谷 P2672 推销员

    题目传送门 解题思路: 我们会发现本题有一个特性,就是如果我们走到一个更远的地方,那么近的地方距离原点的距离我们可以忽略. 本题要求最大的疲劳值,所以我们需要排序,第一个想到堆,反正我是先想到堆. 然 ...

  4. 洛谷p2672推销员题解

    日常扯废话: 话说题解里的思路都写得真的是很奈斯啊 但是 代码看不懂确实让人头疼(可能是我太弱了) 就像题解里的第一篇题解代码简洁但是属实看不明白 趁着学姐刚给我讲了知识还热乎赶紧给泥萌说说哈 正文: ...

  5. 洛谷 P2672 推销员(贪心,模拟)

    传送门 解题思路 第一种: 对于选i家,很显然,a值前i-1家的一定会选,所以只需要考虑最后一家的选法.要么是选择a值第i大的(就不管s了),要么选择剩下的中s最大的. 我们把每一家的情况(s和a)存 ...

  6. 【洛谷 p2672】推销员

    推销员[题目链接] 好了为了凑字数先把题目复制一下: 好了题解第一篇正解: 首先输入,莫得什么好说的: scanf("%d",&n); ;i<=n;i++) scan ...

  7. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  8. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  9. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

随机推荐

  1. SVD(奇异值分解)小结

    注:奇异值分解在数据降维中有较多的应用,这里把它的原理简单总结一下,并且举一个图片压缩的例子,最后做一个简单的分析,希望能够给大家带来帮助. 1.特征值分解(EVD) 实对称矩阵 在理角奇异值分解之前 ...

  2. Oracle出现与并行相关的ORA-00600时的调查方法

    出现了 ORA-00600[kxfpqsod_qc_sod], 如何调查呢? 例如:从trace 文件的 Call Stack,可以看到 Error: ORA-600 [kxfpqsod_qc_sod ...

  3. Elasticsearch Java Rest Client API 整理总结 (三)——Building Queries

    目录 上篇回顾 Building Queries 匹配所有的查询 全文查询 Full Text Queries 什么是全文查询? Match 全文查询 API 列表 基于词项的查询 Term Term ...

  4. 命令行模式和python交互模式

    一.命令行模式 在Windows开始菜单选择“命令提示符”,就进入到命令行模式,它的提示符类似C:>:. 二.Python交互模式 在命令行模式下敲命令python,就看到类似如下的一堆文本输出 ...

  5. 软件测试_Loadrunner_APP测试_性能测试_脚本优化_脚本回放

    本文主要写一下在使用Loadrunner录制完毕APP脚本之后如何对脚本进行回放,如有不足,欢迎评论补充. 如没有安装Loadrunner软件,请查看链接:软件测试_测试工具_LoadRunner: ...

  6. Scala基础(1)

    Scala基础语法 声明与定义: val,常量声明                       val  x:T(把x声明成一个类型为T的常量)  x是变量的名字,T是变量的类型          v ...

  7. PAT甲题题解-1011. World Cup Betting (20)-误导人的水题。。。

    题目不严谨啊啊啊啊式子算出来结果是37.975样例输出的是37.98我以为是四舍五入的啊啊啊,所以最后输出的是sum+0.005结果告诉我全部错误啊结果直接保留两位小数就可以了啊啊啊啊 水题也不要这么 ...

  8. 《Linux内核设计与实现》第18章读书整理

    第十八章.调试 18.1 准备开始 如果bug能重现的话,将会有很大的帮助. 18.2 内核中的bug Bug多种多样,产生的原因可以有无数的原因,表象也变化多端. 从隐藏在源代码中的错误到展现在目击 ...

  9. LeetCode 638 Shopping Offers

    题目链接: LeetCode 638 Shopping Offers 题解 dynamic programing 需要用到进制转换来表示状态,或者可以直接用一个vector来保存状态. 代码 1.未优 ...

  10. [Week17] 个人阅读作业

      个人阅读作业Week17 reading buaa software   解决的问题 这是提出问题的博客链接:http://www.cnblogs.com/SivilTaram/p/4830893 ...