沙雕贪心......

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

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

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

然后又发现可能有问题:你可能取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. 20155308《网络攻防》 Exp1 PC平台逆向破解(5)M

    20155308<网络攻防> Exp1 PC平台逆向破解(5)M 逆向及Bof基础实践说明 1.1 实践目标 本次实践的对象是一个名为pwn1的linux可执行文件. 该程序正常执行流程是 ...

  2. 使用HibernateDaoSupport抽取BaseDao

            在开发采用Struts2+Spring+hibernate这三大框架的项目时,我们需要一个抽取一个BaseDao.这个Dao里面CRUD都给封装好,后续的其他Dao直接用它的功能就可以 ...

  3. [UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]

    题意 给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径 ...

  4. 设计模式 笔记 原型模式 prototype

    //---------------------------15/04/07---------------------------- //prototype 原型模式--对象创建型模式 /* 1:意图: ...

  5. 按键精灵对APP自动化测试(下)

    上一篇介绍了安卓app上使用按键精灵的实践,这里再来说说苹果上的app. 由于iOS相关工具对操作系统的限制,目前在iOS10.0.2系统上应用成功. 二.       苹果手机按键精灵APP录制 适 ...

  6. Unity3D Shader 学习笔记(一):初识Shader

    第一节:图形处理器简史 GPU发展简史 GPU英文全称Graphic Procssing Unit. T&L变换和光照流水线 可编程GPU GPU的优点和缺点 第二节:Unity Shader ...

  7. 《杜增强讲Unity之Tanks坦克大战》9-发射子弹时蓄力

    9 发射子弹时蓄力 实现效果如下   image 按下开火键(坦克1为空格键)重置力为最小力,一直按着的时候蓄力,抬起的时候发射.如果按着的时候蓄力到最大,则自动发射,此时在抬起则不会重复发射. 首先 ...

  8. LeetCode 9. Palindrome Number(回文数)

    Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same back ...

  9. yocto-sumo源码解析(三):oe-setup-builddir

    该脚本的主要功能就是创建构建目录并准备一些配置文件,比如conf/local.conf,conf/bblayer.conf 1. 检测BUILDDIR环境变量是否设置好(在本系列分享第二节已经知道:B ...

  10. 转-PHP 设计模式 之策略模式 应用场景 Strategy Pattern

    一.前言 关于设计模式的文章,园子里实在是太多太多,而且讲解的也非常精彩,那为什么我还要在这里记录下这篇文章?本文以实际项目应用“自己动手写工具--XSmartNote”为切入点,来讲述策略模式的应用 ...