Codeforces Round #821 (Div. 2)
Dashboard - Codeforces Round #821 (Div. 2) - Codeforces
A. Consecutive Sum
思路
- 贪心
选择一个连续 k k k个,因此等价于找到 m o d k = 0 , 1 , 2.. , k − 1 mod\ k=0,1,2..,k-1 mod k=0,1,2..,k−1 的最大的 a a a 的和。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n >> k;
for (int i = 1; i <= n; i ++) cin >> a[i];
LL res = 0;
for (int i = 1; i <= k; i ++) {
int mx = 0;
for (int j = i; j <= n; j += k)
mx = max(mx, a[j]);
res += mx;
}
cout << res << '\n';
}
return 0;
}
B. Rule of League
思路
- 构造
由于第一轮一定有一个人输因此 x , y x,y x,y 里必须有一个 0 0 0,假设 x ! = 0 x!=0 x!=0如果接下来等价于是否让每个人均赢 0 / x 0/x 0/x轮,判断 x ∣ n − 1 x|n-1 x∣n−1是否成立即可,然后模拟就行。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
int x, y; cin >> n >> x >> y;
if ((x && y) || (!x && !y)) cout << -1 << '\n';
else {
if (x < y) swap(x, y);
if ((n - 1) % x != 0) cout << -1 << '\n';
else {
int cnt = (n - 1) / x;
int id = 2;
while (cnt) {
for (int i = 1; i <= x; i ++) cout << id << ' ';
id += x;
cnt --;
}
cout << '\n';
}
}
}
return 0;
}
C. Parity Shuffle Sorting
思路
- 贪心
假设有 1 , 2 , 1 1,2,1 1,2,1 我们发现无论如何都可以让 2 → 1 2\to 1 2→1,因此先将 a 1 , a n a_1,a_n a1,an 搞成一样的,然后再将 i ∈ [ 2 , n − 1 ] i\in [2,n-1] i∈[2,n−1]都搞成和首尾一样的即可。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
vector<PII> res;
if (a[1] != a[n])
if ((a[1] + a[n]) & 1) a[n] = a[1], res.push_back({1, n});
else a[1] = a[n], res.push_back({1, n});
for (int i = 2; i < n; i ++) {
if ((a[i] + a[1]) & 1) res.push_back({1, i});
else res.push_back({i, n});
}
cout << res.size() << '\n';
for (auto t : res) cout << t.x << ' ' << t.y << '\n';
}
return 0;
}
D2. Zero-One (Hard Version)
题意
给你两个字符串 a , b a,b a,b。你可以对 a a a 串进行如下操作,选择 [ l , r ] [l,r] [l,r] 将 a l ⊕ 1 , a r ⊕ 1 a_l\oplus 1,a_r\oplus 1 al⊕1,ar⊕1,如果 l + 1 = = r l+1==r l+1==r 花费 x x x,否则花费 y y y,问你将 a a a 变成 b b b 的最小花费是多少。
思路
- d p dp dp
由于一次改变两个位置的值,因此当不同的位置为 o d d odd odd 的时候无解。
首先 e a s y v e r s i o n easy\ version easy version有 x ≥ y x\ge y x≥y 且 n ≥ 5 n\ge 5 n≥5,因此我们直接贪心,设不同位置有 c n t cnt cnt个,如果 c n t = = 2 cnt==2 cnt==2 且相邻 我们有两种操作方法,直接用 x x x,或者用两个 y y y,其余情况直接用 y y y 成对消除即可。
对于 D 2 D2 D2,考虑 y > x y>x y>x 的情况就不好贪心了,我们先将 a a a和 b b b不同的位置取出来放到 c c c数组中,考虑 d p dp dp设 f [ l ] [ r ] f[l][r] f[l][r]:将 l , r l,r l,r 这个区间所有不同的位置消除的最小操作数(注意这里 的 l , r l,r l,r均是 c c c中的下标),那么对于 f [ l ] [ r ] f[l][r] f[l][r] 可以从哪些子状态转移过来呢,即考虑前一个操作,这里由于 y > x y>x y>x,如果用 y y y的话区间一定越长越优,否则可能被连续的 x x x 顶替掉,而如果操作相邻的话中间和两边均一样,因为会被子状态弄到。所以只会从 f [ l + 1 ] [ r − 1 ] , f [ l + 2 ] [ r ] , f [ l ] [ r − 2 ] f[l+1][r-1],f[l+2][r],f[l][r-2] f[l+1][r−1],f[l+2][r],f[l][r−2] 转移过来。
对于任意两个点 ( i , j ) (i,j) (i,j) 合并,会有一下情况,如果 i + 1 = j i+1=j i+1=j 可以花费 m i n ( x , 2 × y ) min(x,2\times y) min(x,2×y) ,如果 i + 1 ! = j i+1!=j i+1!=j有 m i n ( y , ( j − i ) × x ) min(y,(j-i)\times x) min(y,(j−i)×x),因此转移的时候算一下贡献 即可。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
vector<int> ve;
LL x, y;
LL calc(int l, int r) {
if (l + 1 == r) return min(x, y * 2);
return min(y, x * (r - l));
}
LL f[5010][5010];
LL dfs(int l, int r) {
if (r < l) return 0;
if (f[l][r] != -1) return f[l][r];
LL res = 1e18;
res = min(res, dfs(l, r - 2) + calc(ve[r - 1], ve[r]));
res = min(res, dfs(l + 2, r) + calc(ve[l], ve[l + 1]));
res = min(res, dfs(l + 1, r - 1) + calc(ve[l], ve[r]));
return f[l][r] = res;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n >> x >> y;
string s, t; cin >> s >> t;
ve.clear();
for (int i = 0; i <= n; i ++)
for (int j = 0; j <= n; j ++)
f[i][j] = -1;
for (int i = 0; i < n; i ++)
if (s[i] != t[i]) ve.push_back(i + 1);
if (ve.size() & 1) cout << -1 << '\n';
else {
if (ve.size() == 0) cout << 0 << '\n';
else if (ve.size() == 2) cout << calc(ve[0], ve[1]) << '\n';
else if (y <= x) cout << ve.size() / 2 * y << '\n';
else cout << dfs(0, ve.size() - 1) << '\n';
}
}
return 0;
}
E. Conveyor
题意
给你 x × y x\times y x×y的的矩阵,每个格点的传送带一开始都是向右,第 0 0 0秒 ( 1 , 1 ) (1,1) (1,1) 有一个箱子,之后每一秒都会从 ( 0 , 0 ) (0,0) (0,0) 放置一个箱子,每一秒如果 ( i , j ) (i,j) (i,j)上有箱子话,会将箱子移动到指向的格点,然后向右的会变成指向上,向上的会指向右,给你 q q q 个询问,每次 t , x , y t,x,y t,x,y,问你第 t t t秒的时候 ( x , y ) (x,y) (x,y)上是否右箱子。
思路
- 思维,前缀和优化
想知道第 t t t秒的时候 ( x , y ) (x,y) (x,y)是否有箱子不好判断,但是我们可以求 ( i , j ) (i,j) (i,j) 在 t t t 秒内有多少个箱子经过假设为 c n t i , j cnt_{i,j} cnti,j,假设我们求出了 c n t i , j cnt_{i,j} cnti,j了,那么他会有一半向右边走,一半向下走,由于先向右,再向下,因此 c n t i , j + 1 + = c n t i , j + 1 2 cnt_{i,j+1}+=\frac{cnt_{i,j}+1}{2} cnti,j+1+=2cnti,j+1, c n t i + 1 , j + = c n t i , j 2 cnt_{i+1,j}+=\frac{cnt_{i,j}}{2} cnti+1,j+=2cnti,j,由于从 ( 1 , 1 ) → ( x , y ) (1,1)\to(x,y) (1,1)→(x,y)需要 x + y − 1 x+y-1 x+y−1秒,因此只有 t − ( x + y − 1 ) t-(x+y-1) t−(x+y−1)个箱子可能到第 ( x , y ) (x,y) (x,y)这个点,所以我们模拟一下 t t t 秒经过了多少个,减去 t − 1 t-1 t−1秒经过了多少个,减一下就知道第 t t t秒是否有箱子停在这里了。
Code
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL a[150][150];
int g(LL t, int x, int y) {
memset(a, 0, sizeof a);
a[0][0] = max(t - (x + y) + 1, 0ll);
for (int i = 0; i <= x; i ++)
for (int j = 0; j <= y; j ++) {
a[i + 1][j] += a[i][j] / 2;
a[i][j + 1] += a[i][j] - a[i][j] / 2;
}
return a[x][y];
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
LL t; cin >> t >> n >> m;
cout << (g(t, n, m) - g(t - 1, n, m) > 0 ? "YES" : "NO") << '\n';
}
return 0;
}
867

被折叠的 条评论
为什么被折叠?



