Codeforces Round 924 (Div. 2)
1928D - Lonely Mountain Dungeons
题意:
有 个种族,第 个种族 个生物,现在要将这些生物分成若干组,每一对不在同一组但是同一种族的生物会对这种分组的价值贡献 ,如果分了 组,则价值要减去 ,求最大价值。
思路:
对每种生物单独考虑。
假设已知分了 组,显然对于 ,分成若干个 最优。
具体的,设 ,则我们分 组 个,分 组 个,总共有 。
总贡献应该是个是个单峰函数。
于是我们可以三分,当然二分会更好些一点,每次判断 与 的关系判断最大值在哪个区间即可。
时间复杂度 。
考虑到生物总数比较少,我们也可以直接对每个生物枚举 ,这样做就不用管他单不单峰了。
点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
int n, b, x;
int c[N] = {0};
long long cmb(int m) {
return 1ll * m * (m - 1) / 2;
}
long long chk(int k) {
long long ans = 0ll;
for (int i = 1; i <= n; i++) {
long long d = c[i] / k;
long long m = c[i] % k;
ans += cmb(c[i]);
if (c[i] >= k)
ans -= m * cmb(d + 1) + (k - m) * cmb(d);
}
return ans * b - 1ll * (k - 1) * x;
}
void slv() {
cin >> n >> b >> x;
int mx = 0;
for (int i = 1; i <= n; i++)
cin >> c[i], mx = max(mx, c[i]);
int l = 1, r = mx + 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (chk(mid - 1) <= chk(mid))
l = mid;
else
r = mid;
}
//cout << l << endl;
cout << chk(l) << endl;
}
int main() {
int T;
cin >> T;
while (T--)
slv();
return 0;
}
1928E - Modular Sequence
题意:
长度序列 满足: 或 ,。现在给定 ,求出一个序列 满足上述性质,第一个数为 且所有数之和为 。
思路:
显然最终答案是 和若干个 的形式。
先将所有 减去,再将所有数除以 ,记 。
现在答案就是 加上若干个 。
可以枚举 ,现在判断能否有若干个等差序列和为 。
值域不大,考虑 。设 表示和为 ,所有等差序列至少几个元素。假设最少 个,则比 大的都可以通过补 实现。
直接正着转移,等差序列的和是平方级别的,所有总时间复杂度是 。
于是就完事儿了,输出方案倒着推一遍即可。
点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
int n, x, y, s;
int dp[N] = {0};//dp[i] 表示最少几个元素的若干个等差序列和为 i
void DP() {
for (int i = 0; i <= s; i++)
dp[i] = inf;
dp[0] = 0;
for (int i = 0; i <= s; i++)
for (int j = i + 1, k = 1; j <= s; k++, j += k)
dp[j] = min(dp[j], dp[i] + k + 1);
}
void slv() {
cin >> n >> x >> y >> s;
DP();
int r = x % y;
for (int i = 1; i <= n; i++) {
//从 x, x + 1, x + 2, ..., x + (i - 1)
int res = s;
if (1ll * (i - 1) * i / 2 * y + 1ll * x * i + 1ll * (n - i) * r > res)
continue;
res -= 1ll * (i - 1) * i / 2 * y + 1ll * x * i + 1ll * (n - i) * r;
if (res % y != 0)
continue;
res /= y;
if (dp[res] <= n - i) {
cout << "YES" << endl;
for (int j = 1; j <= i; j++)
cout << x + (j - 1) * y << " ";
int cur = res;
while (cur > 0) {
for (int p = cur - 1, j = 1; p >= 0; j++, p -= j)
if (dp[cur] == dp[p] + j + 1) {
for (int k = 0; k <= j; k++)
cout << r + k * y << " ";
cur = p;
break;
}
}
for (int j = 1; j <= n - i - dp[res]; j++)
cout << r << " ";
cout << endl;
return;
}
}
cout << "NO" << endl;
}
int main() {
int T;
cin >> T;
while (T--)
slv();
return 0;
}
1928F - Digital Patterns
题意:
给定两个序列 和 ,两个序列构成一个 表格, 的价值定义为 ,若干次对 或 区间加,要求每次修改完后输出表格中有多少个子正方形,满足内部四相邻的点价值不同。
。
思路:
很有启发性的一道题。
首先观察发现,所有 和 的位置将表格分成若干个块,内部的所有子正方形都满足条件,任何在两个块的子正方形都不满足条件。
我们假设对于一个块长宽为 ,则贡献就是:
这个推导过程可以直接全拆开再合并,反正最终能得到这个结果。
我们考虑四个数列 。
这样构造数列会使得 。注意这是 的情况,否则 要对调一下。
现在考虑两个序列分成了若干块,分别长度为 和 ,则答案为:
对于固定的 ,我们考虑怎么求 ,按照上面的拆开就是:
所以我们可以维护 的前缀和以及 和 ,将两个序列按从小到大来存,可以用 。
一个数 的贡献就是上面的式子,我们通过快速计算贡献,具体可以用线段树来存前缀和值,一次修改改变常数个,所以最终时间复杂度是 的。
需要卡一下常。
点击查看代码
#include <iostream>
#include <cstdio>
#include <set>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3e5 + 5;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
void read(int &x) {
x = 0;
int f = 1;
char ch = getchar();
while (ch > '9' || ch < '0') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0')
x = x * 10 + (ch - '0'), ch = getchar();
x = f * x;
}
void readLL(long long &x) {
x = 0;
int f = 1;
char ch = getchar();
while (ch > '9' || ch < '0') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0')
x = x * 10 + (ch - '0'), ch = getchar();
x = f * x;
}
void write(long long x) {
if (x < 0)
putchar('-'), write(-x);
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int n, m, q;
/*long long A(int x) {
return 1;
}*/
long long B(int x) {
return x;
}
long long C(int x) {
return 1ll * x * (x + 1) / 2;
}
long long D(int x) {
return 1ll * x * (x + 1) / 2 * (2ll * x + 1) / 3 - 1ll * x * (x + 1) / 2 * x;
}
struct SegTree {
long long val[N * 4];
#define ls (x << 1)
#define rs (x << 1 | 1)
#define mid ((lx + rx) >> 1)
void pushup(int x) {
val[x] = val[ls] + val[rs];
}
void build(int x, int lx, int rx) {
if (lx + 1 == rx) {
val[x] = 0ll;
return;
}
build(ls, lx, mid), build(rs, mid, rx);
pushup(x);
}
void mdf(int x, int lx, int rx, int pos, long long v) {
if (lx + 1 == rx) {
val[x] += v;
return;
}
(pos < mid) ? mdf(ls, lx, mid, pos, v) : mdf(rs, mid, rx, pos, v);
pushup(x);
}
long long qry(int x, int lx, int rx, int l, int r) {
if (rx <= l || r <= lx)
return 0ll;
if (l <= lx && rx <= r)
return val[x];
return qry(ls, lx, mid, l, r) + qry(rs, mid, rx, l, r);
}
SegTree () {}
SegTree (int _n) {
build(1, 1, _n + 1);
}
#undef ls
#undef rs
#undef mid
};
SegTree xsta, xstb, xstc, xstd;
SegTree ysta, ystb, ystc, ystd;
long long x[N] = {0}, y[N] = {0};
set<int> nx, ny;
long long tot = 0ll;//总贡献
//nx, ny 存 x[i] = x[i + 1] 或 y[i] = y[i + 1] 的 i (默认x[n] = x[n + 1] 和 y[m] = y[m + 1])
//转化成差分,存所有 d[i] = 0 的 i - 1
long long Fx(int t) {
long long sum = 0ll;
sum += 1ll * ystd.qry(1, 1, m + 1, 1, t + 1);
sum += B(t) * ystc.qry(1, 1, m + 1, 1, t + 1);
sum += C(t) * ystb.qry(1, 1, m + 1, t + 1, m + 1);
sum += D(t) * ysta.qry(1, 1, m + 1, t + 1, m + 1);
return sum;
}
long long Fy(int t) {
long long sum = 0ll;
sum += 1ll * xstd.qry(1, 1, n + 1, 1, t + 1);
sum += B(t) * xstc.qry(1, 1, n + 1, 1, t + 1);
sum += C(t) * xstb.qry(1, 1, n + 1, t + 1, n + 1);
sum += D(t) * xsta.qry(1, 1, n + 1, t + 1, n + 1);
return sum;
}
void setX(int t, int v) {
xsta.mdf(1, 1, n + 1, t, v);
xstb.mdf(1, 1, n + 1, t, v * B(t));
xstc.mdf(1, 1, n + 1, t, v * C(t));
xstd.mdf(1, 1, n + 1, t, v * D(t));
}
void setY(int t, int v) {
ysta.mdf(1, 1, m + 1, t, v);
ystb.mdf(1, 1, m + 1, t, v * B(t));
ystc.mdf(1, 1, m + 1, t, v * C(t));
ystd.mdf(1, 1, m + 1, t, v * D(t));
}
void addX(int pos) {//X 有一个位置满足
auto Pr = nx.lower_bound(pos);
Pr--;
auto Nx = nx.upper_bound(pos);
int A = pos - *Pr, B = *Nx - pos;
tot -= Fx(A + B);
tot += Fx(A) + Fx(B);
setX(A + B, -1);
setX(A, 1), setX(B, 1);
nx.insert(pos);
}
void eraseX(int pos) {//X 有一个位置不满足
auto Pr = nx.lower_bound(pos);
Pr--;
auto Nx = nx.upper_bound(pos);
int A = pos - *Pr, B = *Nx - pos;
tot += Fx(A + B);
tot -= Fx(A) + Fx(B);
setX(A + B, 1);
setX(A, -1), setX(B, -1);
nx.erase(pos);
}
void addY(int pos) {//y 有一个位置满足
auto Pr = ny.lower_bound(pos);
Pr--;
auto Nx = ny.upper_bound(pos);
int A = pos - *Pr, B = *Nx - pos;
tot -= Fy(A + B);
tot += Fy(A) + Fy(B);
setY(A + B, -1);
setY(A, 1), setY(B, 1);
ny.insert(pos);
}
void eraseY(int pos) {//y 有一个位置满足
auto Pr = ny.lower_bound(pos);
Pr--;
auto Nx = ny.upper_bound(pos);
int A = pos - *Pr, B = *Nx - pos;
tot += Fy(A + B);
tot -= Fy(A) + Fy(B);
setY(A + B, 1);
setY(A, -1), setY(B, -1);
ny.erase(pos);
}
int main() {
read(n), read(m), read(q);
for (int i = 1; i <= n; i++)
readLL(x[i]);
for (int j = 1; j <= m; j++)
readLL(y[j]);
//差分
for (int i = n; i >= 1; i--)
x[i] -= x[i - 1];
for (int j = m; j >= 1; j--)
y[j] -= y[j - 1];
//初始
nx.insert(n), ny.insert(m);
nx.insert(0), ny.insert(0);
xsta = SegTree(n);
xstb = SegTree(n);
xstc = SegTree(n);
xstd = SegTree(n);
ysta = SegTree(m);
ystb = SegTree(m);
ystc = SegTree(m);
ystd = SegTree(m);
setX(n, 1), setY(m, 1);
for (int k = 1; k <= min(n, m); k++)
tot += 1ll * k * k + 1ll * (max(n, m) - min(n, m)) * k;
for (int i = 2; i <= n; i++)
if (x[i] == 0)
addX(i - 1);
for (int j = 2; j <= m; j++)
if (y[j] == 0)
addY(j - 1);
write(tot);
putchar('\n');
for (int i = 1; i <= q; i++) {
int t, l, r, v;
read(t), read(l), read(r), read(v);
if (t == 1) {
if (x[l] == 0 && l > 1)
eraseX(l - 1);
if (x[r + 1] == 0 && r < n)
eraseX(r);
x[l] += v, x[r + 1] -= v;
if (x[l] == 0 && l > 1)
addX(l - 1);
if (x[r + 1] == 0 && r < n)
addX(r);
}
else {
if (y[l] == 0 && l > 1)
eraseY(l - 1);
if (y[r + 1] == 0 && r < m)
eraseY(r);
y[l] += v, y[r + 1] -= v;
if (y[l] == 0 && l > 1)
addY(l - 1);
if (y[r + 1] == 0 && r < m)
addY(r);
}
write(tot);
putchar('\n');
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现