Codeforces Round #750 (Div. 2)
Dashboard - Codeforces Round #750 (Div. 2) - Codeforces
A. Luntik and Concerts
思路
- 贪心
由于 a , b , c ≥ 1 a,b,c\ge 1 a,b,c≥1,因此 3 3 3的影响一定可以被 1 , 2 1,2 1,2抵消掉,因此就是看剩下的 1 , 2 1,2 1,2是否可以均分,因此左右的差不会超过 1 1 1,贪心的来想如果可以为 0 0 0则一定有一种解可以让其 均分,因此直接输出 ( a + b × 2 + c × 3 ) % 2 (a+b\times 2+c\times 3)\%2 (a+b×2+c×3)%2即可。
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[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> a[1] >> a[2] >> a[3];
cout << (a[1] + a[2] * 2 + a[3] * 3) % 2 << '\n';
}
return 0;
}
// 5 1 2 2
// 1 2 2
// 3 1 2
//
B. Luntik and Subsequences
思路
- 简单计数
对于 1 1 1 选一个即可,对于每一个 0 0 0 可选可不选,因此方案为: c n t 1 × 2 c n t 0 cnt_1\times 2^{cnt_0} cnt1×2cnt0
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;
int cnt1 = 0, cnt0 = 0;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
if (a[i] == 1) cnt1 ++;
else if (!a[i]) cnt0 ++;
}
cout << ((LL)cnt1 * (1ll << cnt0)) << '\n';
}
return 0;
}
C. Grandma Capa Knits a Scarf
思路
- 暴力,贪心
暴力枚举将 [ ′ a ′ , ′ z ] ['a','z] [′a′,′z]都删掉的情况,然后判断剩下的是否是回文串,如果可以的话将他们的位置提取出来,得到一个一个的间隔,由于尽量少删,因此尽量在间隔中对称的合法加入即可。
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];
bool check(string t) {
int l = 0, r = t.size() - 1;
while (l < r) {
if (t[l] != t[r]) return false;
l ++, r --;
}
return true;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n;
string str; cin >> str;
int res = INF;
for (int j = 0; j < 26; j ++) {
string t = "";
int cnt = 0;
vector<int> pos, has;
vector<bool> st(n + 1);
for (int i = 0; i < n; i ++)
if (str[i] - 'a' != j)
t += str[i], has.push_back(i + 1);
else cnt ++, st[i + 1] = true;
if (check(t)) {
int l = 0, r = t.size() - 1;
int lastl = 0, lastr = n + 1;
while (l <= r) {
int lcnt = 0, rcnt = 0;
for (int i = lastl + 1; i <= has[l]; i ++)
if (st[i]) lcnt ++;
for (int i = has[r]; i < lastr; i ++)
if (st[i]) rcnt ++;
cnt -= min(lcnt, rcnt) * 2;
lastl = has[l], lastr = has[r];
l ++, r --;
}
if (t.size() % 2 == 0 && t.size()) {
l --, r ++;
int ttt = 0;
for (int i = has[l]; i <= has[r]; i ++)
if (st[i]) ttt ++;
cnt -= ttt;
}
res = min(res, cnt);
}
}
cout << (res == INF ? -1 : res) << '\n';
}
return 0;
}
D. Vupsen, Pupsen and 0
思路
- 构造
从小样例入手,例如只有 1 , 2 1,2 1,2 则我们将他们调换且其中一个加负号即可,对于长一些的序列我们将其转化成小样例的情况,即如果是偶数则两两合并即可,如果是奇数则最后剩三个,将其中两个合并然后和剩余的构成一个对(注意这里要保证两个数合并后和不为 0 0 0,因为 b b b不能为 0 0 0,直接暴力枚举所有情况选一个合法的即可)。
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;
PII a[N];
int sgn(int x) {
if (x > 0) return 1;
return 0;
}
PII g(int x, int y) {
if (sgn(x) == sgn(y)) return {y, -x};
else return {abs(y), abs(x)};
}
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].x, a[i].y = i;
vector<int> res(n + 1);
if (n % 2 == 0) {
for (int i = 1; i <= n; i += 2) {
PII t = g(a[i].x, a[i + 1].x);
res[i] = t.x, res[i + 1] = t.y;
}
}
else {
for (int i = 1; i + 1 <= n - 3; i += 2) {
PII t = g(a[i].x, a[i + 1].x);
res[i] = t.x, res[i + 1] = t.y;
}
if (a[n - 2].x + a[n - 1].x) {
PII t = g(a[n - 2].x + a[n - 1].x, a[n].x);
res[n - 2] = t.x, res[n - 1] = t.x, res[n] = t.y;
}
else if (a[n - 2].x + a[n].x) {
PII t = g(a[n - 2].x + a[n].x, a[n - 1].x);
res[n - 2] = t.x, res[n - 1] = t.y, res[n] = t.x;
}
else {
PII t = g(a[n].x + a[n - 1].x, a[n - 2].x);
res[n - 2] = t.y, res[n - 1] = t.x, res[n] = t.x;
}
}
for (int i = 1; i <= n; i ++) cout << res[i] << " \n"[i == n];
}
return 0;
}
E. Pchelyonok and Segments
题意
给你一个 n n n的数组 a a a,让你选择一个最大的 k k k,且满足你可以从左到右选择 k k k个区间,满足第 i i i区间 满足 [ l i , r i ] [l_i,r_i] [li,ri]的长度为 k − i + 1 k-i+1 k−i+1, i ∈ [ 1 , k − 1 ] s i < s i + 1 i\in [1,k-1]\ \ s_i<s_{i+1} i∈[1,k−1] si<si+1
思路
- 暴力 d p dp dp
由于要满足 ( k + 1 ) × k / 2 ≤ n (k+1)\times k/2 \le n (k+1)×k/2≤n,因此 k k k是 n \sqrt n n级别的,所以考虑 O ( n n ) O(n\sqrt n) O(nn)的 d p dp dp。发现当前的需要用到后面的状态,因此考虑从后往前 d p dp dp,设 f [ i ] [ j ] f[i][j] f[i][j]: [ i , n ] [i,n] [i,n]最左边连续选 j j j个的最大区间和是多少,它的后继按照选不选第 i i i个来划分,即 f [ i + 1 ] f[i+1] f[i+1]和 ∑ k = i i + j − 1 a k \sum_{k=i}^{i+j-1}a_k ∑k=ii+j−1ak(由于题目要求要满足 ∑ k = i i + j − 1 a k < f [ i + j ] [ j − 1 ] \sum_{k=i}^{i+j-1}a_k<f[i+j][j-1] ∑k=ii+j−1ak<f[i+j][j−1]),最好检查一下 f [ 1 ] [ k ] f[1][k] f[1][k]是否大于 0 0 0即可。
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];
LL s[N];
int f[N][500];
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], s[i] = s[i - 1] + a[i];
// (1 + i) * i <= 2n
for (int i = 1; (LL)i * (i + 1) <= n * 2; i ++) f[n + 1][i] = -INF;
f[n + 1][0] = INF;
for (int i = n; i; i --) {
for (int j = 0; (LL)j * (j + 1) <= n * 2; j ++) {
f[i][j] = f[i + 1][j];
if (j && i + j - 1 <= n && s[i + j - 1] - s[i - 1] < f[i + j][j - 1]) f[i][j] = max(1ll * f[i][j], s[i + j - 1] - s[i - 1]);
}
}
int res = 1;
for (int i = 1; (LL)i * (i + 1)<= n * 2; i ++)
if (f[1][i] > 0) res = i;
cout << res << '\n';
}
return 0;
}
F2. Korney Korneevich and XOR (hard version)
题意
给你一个长度为 n n n的序列,请你求出它的每一个上升子序列的异或和,并找出有多少个不同的值,并从小到大输出他们。
思路
- d p dp dp
先考虑 F 1 F1 F1,由于 a i a_i ai很小 因此最后异或 出来的值域 V V V也很小,设 f [ i ] f[i] f[i]:序列异或和为 i i i且最后一个数的最小值,从前往后对于每一个 a i a_i ai 我们暴力的枚举 所有的值域如果 f [ j ] < a i f[j]<a_i f[j]<ai就可以用 a i a_i ai去更新 f [ j ⊕ a i ] f[j\oplus a_i] f[j⊕ai],即复杂度为 O ( n × V ) O(n\times V) O(n×V),这个复杂度是没法通过 F 2 F2 F2的。
考虑我们的转移瓶颈在于枚举值域,因此设 u p d [ i ] upd[i] upd[i]:枚举到目前位置能更新 i i i的所有的子序列异或和的值都有什么,然后对于 a i a_i ai 等价于用 u p d [ a i ] upd[a_i] upd[ai] 存的每一个值 j j j 来和 a i a_i ai异或产生贡献,即 t = j ⊕ a i t=j\oplus a_i t=j⊕ai ,判断这个值能够更新 u p d upd upd什么,由于 t t t 是以 a i a_i ai 结尾的,因此可以用 t t t 更新 ( a i , V ] (a_i,V] (ai,V],发现这个更新具有后缀性质,如果原来用 t t t更新过 ( a i , V ] (a_i,V] (ai,V]这些位置了,那么下一次就不需要从 V V V 开始,可以从 a i a_i ai开始,所以搞个东西记录一下每个状态现在最大更新点是什么即可,因此每个值只会对应 V V V个状态,且值域有 V V V个状态,并且不会重复更新,因此这样做复杂度就降到 O ( n + V 2 ) O(n+V^2) O(n+V2)。
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 = 1e6 + 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 suf[N];
vector<int> upd[N];
bool st[N];
int main() {
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (int i = 0; i <= 8192; i ++) upd[i].push_back(0), suf[i] = 8192;
st[0] = true;
int res = 1;
for (int i = 1; i <= n; i ++) {
int x; cin >> x;
for (auto t : upd[x]) {
int v = t ^ x;
res += !st[v], st[v] = true;
while (suf[v] > x) upd[suf[v] --].push_back(v);
}
upd[x].clear();
}
cout << res << '\n';
for (int i = 0; i <= 8192; i ++)
if (st[i]) cout << i << ' ';
cout << '\n';
return 0;
}
// n % p