Codeforces Round 917 (Div. 2)
A. Least Product#
- 存在
, ,不需要任何操作。 - 负数个数为偶数(包括0),
,把任意一个改为 。 - 负数个数为奇数,
,不需要任何操作。
void solve() {
int n;
cin >> n;
vector<int> b, c, d;
for(int i = 0; i < n; ++ i) {
int x;
cin >> x;
if(x > 0) b.push_back(x);
else if(x == 0) c.push_back(x);
else d.push_back(x);
}
if(c.size()) puts("0");
else if(d.size() % 2 == 0) puts("1\n1 0");
else puts("0");
}
B. Erase First or Second Letter#
枚举每个字符
因为第一个元素已经确定,所以只能删
先前出现过的字符直接
void solve() {
int n;
string s;
cin >> n >> s;
ll ans = 0;
vector<bool> vis(26, 0);
for(int i = 0; i < n; ++ i) {
if(!vis[s[i] - 'a']) {
vis[s[i] - 'a'] = 1;
ans += (n - i);
}
}
cout << ans << '\n';
}
C. Watering an Array#
考虑把数组清零后怎么贪。
在若干次操作后,整个数组一定是非增的,因此每一天最多有一个位置满足条件。
显然,每两天就进行一次
现在回过来处理原始数组。
枚举操作到第
一次清零最多能得到
因此当
注意
void solve() {
int n, k, d;
cin >> n >> k >> d;
vector<int> a(n + 1), v(k);
int ans = 0;
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
if(a[i] == i) ++ ans;
}
for(int &x : v) cin >> x;
ans += (d - 1) >> 1;
for(int i = 0; i < 2 * n; ++ i) {
if(i == d - 1) break;
int res = 0;
for(int j = 1; j <= v[i % k]; ++ j) ++ a[j];
for(int j = 1; j <= n; ++ j) if(a[j] == j) ++ res;
res += (d - i - 2) >> 1;
ans = max(ans, res);
}
cout << ans << '\n';
}
D. Yet Another Inversions Problem#
E. Construct Matrix#
一个显然的性质:若得到一组关于 的解,则对答案整个取反后能得到 的解。#
首先考虑无解。
- 若
为奇数,无解。 - 若
且 或 ,无解。
我们不妨假设剩下的情况都是有解的。
情况一:
void case1() { // k == n
for(int i = 1; i <= n; ++ i) a[i][i] = 1;
}
情况二:
- 在一行(列)里添加偶数个
不会对原异或值有任何改动。
根据这条性质,容易想到用
void case2() { // k % 4 == 0
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j <= n; ++ j) {
if(!a[i][j] && k) {
a[i][j] = a[i + 1][j] = a[i][j + 1] = a[i + 1][j + 1] = 1;
k -= 4;
}
}
}
}
情况三:
去思考如何把情况三转化到情况二。
我们可以在网格的左上角构造如下
把
按照上述构造方法需要考虑
如果
void Reverse (){
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= n; ++ j)
a[i][j] ^= 1;
}
void case3() { // k % 4 == 2
bool f = 0;
if(k > n * n - 9) f = 1, k = n * n - k;
a[1][1] = a[1][2] = a[2][1] = a[2][3] = a[3][2] = a[3][3] = 1;
k -= 6;
for(int i = 1; i <= n; ++ i) {
for(int j = 1; j <= n; ++ j) {
if(i <= 4 && j <= 4) continue;
if(!a[i][j] && k) {
a[i][j] = a[i + 1][j] = a[i][j + 1] = a[i + 1][j + 1] = 1;
k -= 4;
}
}
}
if(f) Reverse();
}
F. Construct Tree#
先把
- 性质一:对于任意两条边
,一定存在至少一条路径同时通过这两条边。
容易得到,若
,则一定无解。
- 性质二:若存在边集
(不含 )的子集 满足 ,则一定有解。
把
中所有边构成一条链挂在根节点上
对于剩余的边则一个一个挂上去。
注意:此时已经将性质一中的无解情况去掉了,可以证明此时满足条件。。
- 性质三:设
为边集 (不含 )的两个互不重合的子集。若 与 的和都大于 ,则一定有解。
把
中所有边构成一条链挂在根节点上, 同样操作。
对于剩余的边则一个一个挂上去。
可以证明此时满足条件。
对于性质三,我们可以用
对于性质二,可以用
联想到
由于状态是
int n, d, a[N];
bitset<N> dp[N];
void solve() {
cin >> n >> d;
for(int i = 1; i <= n; ++ i) cin >> a[i];
sort(a + 1, a + n + 1);
if(a[n] + a[n - 1] > d) {
puts("No");
return;
}
for(int i = 0; i <= d; ++ i) dp[i].reset();
dp[0][0] = 1;
for(int i = 1; i < n; ++ i) {
for(int j = d; j >= 0; -- j) {
if(j + a[i] <= d) dp[j + a[i]] |= dp[j];
dp[j] |= dp[j] << a[i];
}
}
bool ok = dp[0][d - a[n]];
for(int i = a[n]; i <= d - a[n]; ++ i) ok |= dp[i][d - i];
puts(ok ? "Yes" : "No");
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】