YC339A [ 20240915 CQYC NOIP 模拟赛 T1 ] 演讲(talk)

cxqghzj·2024-09-15 21:54·9 次阅读

YC339A [ 20240915 CQYC NOIP 模拟赛 T1 ] 演讲(talk)

题意#

n 个地点,你可以:

  • 使用 ailen 的代价标记该地点。
  • 使用 bilen 的代价标记该地点并使得 len:=len+1
  • 跳过该地点。

你不需要按照顺序标记,问标记 m 个点的最小代价是多少(可以证明答案是实数)。

n500,aibi

Sol#

注意到一个贪心,就是枚举第二种操作选了多少,然后剩下就贪心选择第一种操作。

这样为什么是错的?因为可以有情况使得一个地点 ai 极小而 bi 需要选择,这个时候只需要选择 ai,换成下一个不是很优的 bj

但是注意到这个东西我们可以考虑 dp,依然是枚举第二种操作的数量,设 fi,j,k 表示前 i 个地点第一种操作的数量为 j 第二种操作的数量为 k

这样是 O(n4) 的,很菜。

考虑一个优化,不难发现最后一次选择的第二种操作之前不会有地点选择第三种操作,也就是被跳过。

于是只需要枚举最后一次的位置就行了,改设为 fi,ji 个地点选择了 j 个第二种操作。

复杂度 O(n3)

Code#

Copy
#include <iostream> #include <algorithm> #include <cstdio> #include <array> #define pii pair <int, int> #define db double using namespace std; #ifdef ONLINE_JUDGE #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; #endif int read() { int p = 0, flg = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') flg = -1; c = getchar(); } while (c >= '0' && c <= '9') { p = p * 10 + c - '0'; c = getchar(); } return p * flg; } void write(int x) { if (x < 0) { x = -x; putchar('-'); } if (x > 9) { write(x / 10); } putchar(x % 10 + '0'); } bool _stmer; #define fi first #define se second const int N = 505, inf = 2e9; array <array <double, N>, N> f; array <pii, N> s; array <array <pii, N>, N> g; bool _edmer; int main() { cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n"; #ifndef cxqghzj freopen("talk.in", "r", stdin); freopen("talk.out", "w", stdout); #endif int n = read(), m = read(); for (int i = 1; i <= n; i++) { s[i].fi = read(), s[i].se = read(); if (!~s[i].se) s[i].se = inf; } sort(s.begin() + 1, s.begin() + 1 + n, [](pii x, pii y) { return x.se < y.se; }); for (int i = 0; i <= n; i++) g[i] = s, sort(g[i].begin() + 1 + i, g[i].begin() + 1 + n); #define upd(x, y) (x = min(x, y)) db ans = 0; for (int i = 1; i <= m; i++) ans += g[0][i].fi; for (int l = 1; l <= m; l++) { for (int i = 0; i <= n; i++) f[i].fill(4e18); f[0][0] = 0; for (int i = 1; i <= n; i++) { for (int j = 0; j <= l; j++) { upd(f[i][j], f[i - 1][j] + (db)s[i].fi / (l + 1)); if (j) upd(f[i][j], f[i - 1][j - 1] + (db)s[i].se / j); } if (i < l) continue; db sum = 0; for (int j = i + 1; j <= m; j++) sum += (db)g[i][j].fi / (l + 1); ans = min(ans, sum + f[i][l]); } } printf("%.6lf\n", ans); return 0; }
posted @   cxqghzj  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
目录