Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics) 题解

codeforces 专栏收录该内容
246 篇文章 0 订阅

A. Even Subset Sum Problem(数学)


在这里插入图片描述

题目

题意:

给定一个由 n n n个正整数组成的数组 a a a。找到其元素的非空子集,使其和为偶数(即,可被 2 2 2整除)或确定不存在这样的子集。

思路:

总共由三种情况:

  • 只要出现一个偶数,那么一定有一个子序列就是它自己。
  • 出现至少两个奇数,那么和一定为偶数。
  • 如果只有一个奇数的情况下,那么此时这个序列才不为偶数。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <deque>
#include <stack>
#include <cctype>
using namespace std;
typedef long long ll;
typedef vector<int> veci;
typedef vector<ll> vecl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template <class T>
inline void read(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return ;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1:1;
    ret = (c == '-') ? 0:(c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return ;
}
inline void outi(int x) {if (x > 9) outi(x / 10);putchar(x % 10 + '0');}
inline void outl(ll x) {if (x > 9) outl(x / 10);putchar(x % 10 + '0');}
const int maxn = 1e2 + 10;
int a[maxn];
int main() {
    int t; read(t); while (t--) {
        int k = 0;
        int n; read(n); for (int i = 1; i <= n; i++) {
            read(a[i]); if (a[i] % 2 == 0) k = i;
        }
        if (k) printf("1\n%d\n", k);
        else if (n == 1) printf("-1\n");
        else printf("2\n1 2\n");
    }
    return 0;
}

B. Count Subrectangles(暴力)


在这里插入图片描述

题目

题意:

给你一个类似矩阵的序列,问你这个序列中有多少个矩形满足面积为 k k k且矩形中只有 1 1 1这个元素。

思路:

我们可以发现先把举行的种类写出来,比如说 6 6 6这个面积,我们就可以分解长宽为 2 ∗ 3 , 1 ∗ 6 2*3,1*6 23,16,然后我们就可以通过遍历 n , m n,m n,m找出各行各列分别有多少个满足这个长宽。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <deque>
#include <stack>
#include <cctype>
using namespace std;
typedef long long ll;
typedef vector<int> veci;
typedef vector<ll> vecl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template <class T>
inline void read(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return ;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1:1;
    ret = (c == '-') ? 0:(c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return ;
}
inline void outi(int x) {if (x > 9) outi(x / 10);putchar(x % 10 + '0');}
inline void outl(ll x) {if (x > 9) outl(x / 10);putchar(x % 10 + '0');}
const int maxn = 4e4 + 10;
int a[maxn], b[maxn];
int main() {
    int n, m, k; read(n), read(m), read(k);
    for (int i = 1; i <= n; i++) {read(a[i]); if (a[i]) a[i] += a[i - 1];}
    for (int i = 1; i <= m; i++) {read(b[i]); if (b[i]) b[i] += b[i - 1];}
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        int cnt1 = 0, cnt2 = 0;
        if (k % i == 0) {
            int x1 = i, x2 = k / i;
            for (int j = 1; j <= n; j++) if (a[j] >= x1) cnt1++;
            for (int j = 1; j <= m; j++) if (b[j] >= x2) cnt2++;
            ans += 1ll * cnt1 * cnt2;
        }
    }
    printf("%lld", ans);
    return 0;
}

C. Unusual Competitions(暴力)


在这里插入图片描述

题目

题意:

我们需要将所有的括号通过一定括号的方式使之成为正确的,我们一次可以将一个区间里面的括号进行不断交换,但是答案需要加上这个区间的长度,问最后最短的长度是多少。

思路:

如果要使之正确,一个左括号肯定会对应一个右括号,我们要每一次的区间长度最少的话,那么就是剔除符合条件的那个区间就行了,最后就是将不符合条件的加起来就行了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <deque>
#include <stack>
#include <cctype>
using namespace std;
typedef long long ll;
typedef vector<int> veci;
typedef vector<ll> vecl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template <class T>
inline void read(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return ;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1:1;
    ret = (c == '-') ? 0:(c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return ;
}
inline void outi(int x) {if (x > 9) outi(x / 10);putchar(x % 10 + '0');}
inline void outl(ll x) {if (x > 9) outl(x / 10);putchar(x % 10 + '0');}
const int maxn = 1e6 + 10;
char s[maxn];
int main() {
    int n; read(n);
    scanf("%s", s + 1);
    int cnt = 0, ans = 0, last = 0;
    for (int i = 1; i <= n; i++) {
        if (s[i] == ')') cnt++;
        else cnt--;
        if (cnt == 0) ans += i - last, last = i;
        if (cnt < 0) last = i + 1;
    }
    if (cnt) printf("-1");
    else printf("%d", ans);
    return 0;
}

D. Present(位运算+二分)


在这里插入图片描述

题目

题意:

我们将所有的数字两个相加后得到的值,在进行异或后得到的就是最终的答案了。

思路:

暴力肯定是不可行的,但是异或有个特性,那就是更具最后 1 1 1的奇偶性得出最后到底是 1 1 1还是 0 0 0,所以对于每一位,我们都求出总共有多少个 1 1 1,所以我们可以先选择一个 i i i,我们要使 b i t i = 1 bit_i=1 biti=1,那么此时就 2 i ≤ a i % 2 i + 1 + a j % 2 i + 1 ≤ 2 i + 1 2^i\leq a_i\%2^{i+1} +a_j\% 2^{i+1}\leq 2^{i+1} 2iai%2i+1+aj%2i+12i+1,所以我们可以枚举每一个 a j a_j aj,然后求出所有可能的值,所以此时需要寻找的 a i a_i ai的区间应该是 [ 2 i − a j , 2 i + 1 − 1 − a j ] [2^i-a_j,2^{i+1}-1-a_j] [2iaj,2i+11aj],我们也可以发现如果数值过大的情况呢,比如两个相加超过了 2 i + 1 2^{i+1} 2i+1,但是依旧有可能出现 b i t i = 1 bit_i=1 biti=1的情况,那就是最终值是 1 i + 1 1 i . . . . . 1_{i+1}1_i..... 1i+11i.....的情况,那么此时的区间就是 [ 2 i + 1 + 2 i − a j , 2 i + 2 − 2 − a j ] [2^{i+1}+2^i-a_j,2^{i+2}-2-a_j] [2i+1+2iaj,2i+22aj]

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <deque>
#include <stack>
#include <cctype>
using namespace std;
typedef long long ll;
typedef vector<int> veci;
typedef vector<ll> vecl;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
template <class T>
inline void read(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return ;
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1:1;
    ret = (c == '-') ? 0:(c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return ;
}
inline void outi(int x) {if (x > 9) outi(x / 10);putchar(x % 10 + '0');}
inline void outl(ll x) {if (x > 9) outl(x / 10);putchar(x % 10 + '0');}
const int maxn = 4e5 + 10;
int a[maxn] = {0};
int main() {
    veci v;
    int n; read(n); for (int i = 1; i <= n; i++) {
        int x; read(x);
        v.push_back(x);
    }
    int ans = 0;
    for (int i = 0; i < 25; i++) {
        for (int j = 0; j < n; j++) a[j] = v[j] % (1 << i + 1);
        sort(a, a + n);
        int cnt = 0;
        for (int j = 1; j < n; j++) {
            cnt += upper_bound(a, a + j, (1 << i + 1) - 1 - a[j]) - lower_bound(a, a + j, (1 << i) - a[j]);
            cnt += upper_bound(a, a + j, (1 << i + 2) - 2 - a[j]) - lower_bound(a, a + j, (1 << i + 1) + (1 << i) - a[j]);
        }
        if (cnt & 1) ans += (1 << i);
    }
    printf("%d", ans);
    return 0;
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值