2024.11.20 CW 模拟赛
T1
算法
区间动态规划.
思路
考虑两个人在一轮中的操作, 先手(执行删除操作的人)希望得分最小化, 后手(执行取数操作的人)希望得分最大化.
显然有如下转移方程:
\[f_{l,r} = \min^r_{i=l} (\max(sum(l,i-1)+f_{i+1,r},sum(i+1,r)+f_{l,i-1}))
\]
边界条件 \(f_{i,i}=0\).
这里我采用的是记忆化搜索实现.
#include "iostream"
using namespace std;
const int N = 5e2 + 10;
int n;
int a[N], pre[N];
int f[N][N];
int solve(int l, int r)
{
if (f[l][r] != 1e9)
return f[l][r];
if (l >= r)
return 0;
else if (r - l + 1 == 2)
return min(a[l], a[r]);
for (int i = l; i <= r; i++)
f[l][r] = min(f[l][r], max(solve(l, i - 1) + pre[r] - pre[i], solve(i + 1, r) + pre[i - 1] - pre[l - 1]));
return f[l][r];
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
pre[i] = pre[i - 1] + a[i];
for (int j = 1; j <= n; j++)
f[i][j] = 1e9;
}
cout << solve(1, n) << '\n';
return 0;
}
T2
算法
二分, 图论.
思路
容易发现, 当自身武力值越高, 能够通过的边越多, 能够收集的货物总量也就越多.
所以答案具有单调性, 可以考虑二分答案.
在 \(check\) 的时候如果遇到比当前武力值大的边直接跳过, 否则继续 dfs.
时间复杂度 \(\mathcal{O}(n \log n)\).
#include "iostream"
using namespace std;
typedef pair<int, int> pii;
#define getchar getchar_unlocked
template <typename T>
inline void read(T &x)
{
x = 0;
char ch = getchar();
while (!isdigit(ch))
ch = getchar();
while (isdigit(ch))
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return;
}
const int N = 1e6 + 1;
int n, W, mx = -1;
int a[N];
basic_string<pii> g[N];
inline void init()
{
read(n), read(W);
for (int i = 2; i <= n; ++i)
read(a[i]);
for (int i = 1; i < n; ++i)
{
int u, v, w;
read(u), read(v), read(w);
g[u] += {v, w};
g[v] += {u, w};
mx = max(mx, w);
}
return;
}
long long tot = 0;
void dfs(int u, int fa, int up)
{
for (pii i : g[u])
{
int v = i.first, w = i.second;
if (v == fa)
continue;
if (w > up)
continue;
tot += a[v];
dfs(v, u, up);
}
return;
}
inline bool check(int x)
{
tot = 0;
dfs(1, 0, x);
return tot >= W;
}
inline void calculate()
{
int l = 0, r = mx, mid, ans;
while (l <= r)
{
mid = l + r >> 1;
if (check(mid))
ans = mid, r = mid - 1;
else
l = mid + 1;
}
printf("%d\n", ans);
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
solve();
return 0;
}
T3
算法
动态规划及其优化, ST 表 / 线段树, 单调队列.
思路
先考虑 30pts.
令 \(f_{i,j}\) 表示到第 i 个的时候已经分了 j 组.
则有以下方程:
\[f_{i,j} = \min (f_{k,j-1} + \max(k+1,i) - \min(k+1,i) + sum(k+1,i))
\]
这样转移是 \(\mathcal{O}(n^3)\) 的, 其中查询 \(\min,\max\) 可以用 ST 表/线段树优化.
60pts.
可以考虑费用提前计算, 删除掉 \(j\) 这维, 则转移方程如下:
\[f_i=\min_{j<i}(f_j+sum(j+1,n)+cost(j+1,i))
\]
转移是 \(\mathcal{O}(n^2)\) 的, 还是不足以通过此题.
100pts.
参考这篇博客 QAQ.
优化大意是将一些无用的状态剔除, 不再使用其进行转移.
#include "iostream"
#include "cmath"
#include "deque"
using namespace std;
template <typename T>
inline void read(T &x)
{
x = 0;
char ch = getchar();
while (ch < '0' or ch > '9')
ch = getchar();
while (ch >= '0' and ch <= '9')
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return;
}
const int N = 1e5 + 1;
int n, W;
int a[N];
class ST
{
protected:
int fmn[N][21], fmx[N][21];
public:
inline void init()
{
for (int i = 1; i <= n; ++i)
fmn[i][0] = fmx[i][0] = a[i];
int p = log2(n);
for (int k = 1; k <= p; ++k)
for (int s = 1; s + (1 << k) <= n + 1; ++s)
{
fmx[s][k] = max(fmx[s][k - 1], fmx[s + (1 << k - 1)][k - 1]);
fmn[s][k] = min(fmn[s][k - 1], fmn[s + (1 << k - 1)][k - 1]);
}
return;
}
inline int query(int l, int r)
{
int k = log2(r - l + 1);
int x = max(fmx[l][k], fmx[r - (1 << k) + 1][k]),
y = min(fmn[l][k], fmn[r - (1 << k) + 1][k]);
return x - y;
}
} st;
long long sum[N];
inline void init()
{
read(n), read(W);
for (int i = 1; i <= n; ++i)
read(a[i]), sum[i] = sum[i - 1] + a[i];
st.init();
return;
}
long long f[N];
deque<int> q;
inline void calculate()
{
f[0] = sum[n];
q.push_back(0);
for (int i = 1; i <= n; ++i)
{
while (!q.empty() and sum[i] - sum[q.front()] > W)
q.pop_front();
f[i] = 1e18;
for (int x : q)
f[i] = min(f[i], f[x] + sum[n] - sum[i] + st.query(x + 1, i));
while (!q.empty() and f[i] <= f[q.back()])
q.pop_back();
q.push_back(i);
}
printf("%lld\n", f[n]);
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现