当前位置: 首页 > news >正文

贪心随笔

目录
  • 贪心
    • 贪心应用
      • P1561 [USACO12JAN] Mountain Climbing S
      • P11323 【MX-S7-T1】「SMOI-R2」Happy Card
    • 反悔贪心
      • P1484 种树
      • AGC018 C Coins
      • P11268 【MX-S5-T2】买东西题
        • Sol 1

贪心

自己中の光線銃 乱射する 強者のナンセンス

オートクチュールで作る 殺しのライセンス

分断を生んじゃった椅子取りゲーム 無痛分娩で授かるベイブ

壮大な内輪ノリを歴史と呼ぶ

选取局部最优解达到全局最优解的算法。

贪心的正确性需要证明,有如下证明方法:

  1. 微扰
  2. 范围缩放
  3. 决策包容
  4. 反证
  5. 数学归纳

贪心应用

P1561 [USACO12JAN] Mountain Climbing S

是一道普通贪心题。

贪心策略是使有牛下山时尽可能使山上有牛。

需要将牛分为 \(U(i) \ge D(i)\)\(U(i) \lt D(i)\) 两种情况,让第二类牛先上能满足贪心。

其他比较简单。时间复杂度 \(\mathcal{O}(n)\)

code
const int N = 2.5e4 + 5;struct node { int up, dw; } a[N];
int n, ut[N], dt[N];bool cmp(node a, node b) {if (a.up < a.dw) {if (b.up < b.dw) return a.up < b.up;else return 1;} else {if (b.up < b.dw) return 0;else return a.dw > b.dw;}
}int main() {read(n);rep(i, 1, n) read(a[i].up, a[i].dw);sort(a + 1, a + n + 1, cmp);rep(i, 1, n) ut[i] = ut[i - 1] + a[i].up;rep(i, 1, n) dt[i] = max(dt[i - 1], ut[i]) + a[i].dw;write(dt[n]);return 0;
}

P11323 【MX-S7-T1】「SMOI-R2」Happy Card

\(\color{#39C5BB}{[EASY]}\)

需要观察到“炸”是三带一,即三张相同的牌可以带任意一张牌。

贪心地尽可能出三带一是对的,这点在模拟出牌后即可发现。

然后将牌分成 \(3\) 个一组,\(2\) 个一组,单独一组,分别讨论答案就好了。

code
const int N = 3e5 + 5;int T, n, v[N];
i64 cnt[4], ans;void init() {cnt[1] = cnt[2] = cnt[3] = 0; ans = 0;
}void solve() {read(n); init();rep(i, 1, n) read(v[i]);rep(i, 1, n) {cnt[3] += v[i] / 3;if (v[i] % 3) cnt[v[i] % 3]++;}if (cnt[3] <= cnt[1]) return write(cnt[3] + (cnt[1] - cnt[3]) + cnt[2], '\n'), void();if (cnt[3] - cnt[1] <= 2 * cnt[2]) return write(cnt[3] + (2 * cnt[2] - (cnt[3] - cnt[1]) + 1) / 2, '\n'), void();ans += cnt[2] * 2 + cnt[1];cnt[3] -= (2 * cnt[2] + cnt[1]);ans += (cnt[3] / 4) * 3; cnt[3] %= 4;if (cnt[3] == 3) ans += 3;else if (cnt[3] == 2 || cnt[3] == 1) ans += 2;write(ans, '\n');
}int main() {read(T);while (T--) solve();return 0;
}

反悔贪心

不需要选最优解,从一个较劣的情况变为最优解。

P1484 种树

反悔贪心板子。

先贪心选最大,然后做一个用于反悔的坑。

变成链表上操作,方便模拟题意。

时间复杂度 \(\mathcal{O}(n\log n)\)

code
const int N = 6e5 + 5;int n, k, a[N];
int pre[N], Next[N];
priority_queue<pii> que;
bool vis[N];
i64 ans;int main() {read(n, k);rep(i, 1, n) read(a[i]);rep(i, 2, n) pre[i] = i - 1;rep(i, 1, n - 1) Next[i] = i + 1;rep(i, 1, n) que.push({a[i], i});while (k) {while (vis[que.top().second]) que.pop();int val = que.top().first, pos = que.top().second;if (val < 0) break;int pval = a[pre[pos]], nval = a[Next[pos]];a[++n] = pval + nval - val; que.push({a[n], n});ans += val, vis[pos] = 1, vis[pre[pos]] = 1, vis[Next[pos]] = 1;Next[pre[pre[pos]]] = n, pre[n] = pre[pre[pos]];Next[n] = Next[Next[pos]], pre[Next[Next[pos]]] = n; k--;}write(ans);return 0;
}

AGC018 C Coins

开始随便选,然后交换即可。

用六个堆维护每个人换成另外两种币的收益。

显然会有两两互换或三人互换的情况。容易证明多人互换的情况可以用前两种情况表示。

容易证明时间复杂度是 \(\mathcal{O}(n\log n)\)。code。

P11268 【MX-S5-T2】买东西题

\(\color{#FFA500}{[NORMAL-]}\)

Sol 1

50 pts 简单,考虑每个优惠券会对那些商品起作用。

发现作用区间为一段后缀,作用形如替换降价价格,考虑用线段树计算答案。

首先将优惠券按限制从大到小排序。然后对于每个优惠券,令它对它起作用区间内降价最少的替换,这样一定不劣。

因为后缀只会变长,这样处理出了局部最优解。

我的错误

考场上觉得需要按降价对优惠券进行排序。

一个很典的问题,局部最优解不是全局最优解。

因为把后面的位置占了,有后效性,而上面的没有。

code
const int N = 1e6 + 5;struct Node { int a, b; } a[N], b[N];
int n, m, c[N], d[N], tr[N << 2];
i64 ans;void up(int rt) { tr[rt] = d[tr[ls]] > d[tr[rs]] ? tr[rs] : tr[ls]; }void build(int rt, int l, int r) {if (l == r) return tr[rt] = l, void();int mid = (l + r) >> 1;build(ls, l, mid), build(rs, mid + 1, r);up(rt);
}void update(int rt, int l, int r, int p, int v) {if (l == r) return d[p] = v, void();int mid = (l + r) >> 1;if (p <= mid) update(ls, l, mid, p, v);else update(rs, mid + 1, r, p, v);up(rt);
}int query(int rt, int l, int r, int L, int R) {if (L <= l && r <= R) return tr[rt];int mid = (l + r) >> 1, pos, val = 1e9 + 5;if (L <= mid) {int p = query(ls, l, mid, L, R);if (d[p] < val) pos = p, val = d[p];}if (mid < R) {int p = query(rs, mid + 1, r, L, R);if (d[p] < val) pos = p;}return pos;
}int main() {read(n, m);rep(i, 1, n) read(a[i].a, a[i].b);rep(i, 1, m) read(b[i].a, b[i].b);sort(a + 1, a + n + 1, [&](Node a, Node b) { return a.a < b.a; });sort(b + 1, b + m + 1, [&](Node a, Node b) { return a.a > b.a; });rep(i, 1, n) c[i] = a[i].a, d[i] = a[i].a - a[i].b;build(1, 1, n);rep(i, 1, m) {int l = lower_bound(c + 1, c + n + 1, b[i].a) - c;if (l > n) continue;int p = query(1, 1, n, l, n);if (d[p] < b[i].b) update(1, 1, n, p, b[i].b);}rep(i, 1, n) ans += a[i].a - d[i];write(ans);return 0;
}
http://www.sczhlp.com/news/1003/

相关文章:

  • ubuntu系统ufw开放端口教程
  • 基础算法随笔
  • 技术跃迁!DVP AirCAMERA _1020摄像头小板赋能开发者构建顶级视觉系统
  • 小工具
  • Ubuntu20.04 安装gcc11 g++11, Ubuntu18.04
  • Forward prop in tensorflow
  • aws 上传自定义证书
  • 空间智能赋能城市低空数字底座及智能网联系统建设
  • 扫描线求矩形周长并的注意事项
  • 微店商品详情接口micro.item_get请求参数响应参数解析
  • 游戏服务器优雅关服设计与实现
  • 思通数科 AI 安监系统:工业园安全监管的 “智能防线”
  • snort入侵检测基础
  • Linux防火墙
  • SAP 后继物料简介
  • SQL注入漏洞
  • 使用mysqlshell查询数据库返回json格式数据
  • Centos中将UTC的时区改为CTS时区
  • MyEMS 开源能源管理系统核心代码解读 023
  • 详解 OpenAI 函数调用(Function Calling):让模型具备数据获取与行动能力
  • 【宝藏贴】HarmonyOS官方模板优秀案例 第1期:便捷生活-购物中心
  • 新一代对象存储 RustFS Python SDK 的使用
  • 扩散模型-PPDM-plus-03 - jack
  • c++ 进制转换
  • 【LeetCode 2】力扣算法:两数相加
  • 测试支持 PolarDB-X(高度兼容 MySQL) 的客户端图形工具
  • Gitlab Runner怎么使用缓存cache加快构建速度
  • 一个38岁程序员的五年之约:软考、重构与独立开发者之路
  • 1.初看代码
  • Tita 新绩效一体化产品:重塑企业绩效管理新范式