[题解][Codeforces]Good Bye 2019 简要题解

  • 构造题好评,虽然这把崩了
  • 原题解

A

题意

  • 二人游戏,一个人有 \(k_1\) 张牌,另一个人 \(k_2\) 张,满足 \(2\le k_1+k_2=n\le 100\),每张牌上有一个数,保证所有的牌上的数互不相同且在 \([1,n]\) 内
  • 每回合双方都会出一张牌,牌上数小的一方的牌会给牌上数大的一方
  • 拿到所有 \(n\) 张牌的一方赢得比赛
  • 求两人都采取最优策略的情况下谁会赢
  • 多组数据,数据组数 \(t\le100\)

做法:贪心

  • 设 \(a\) 和 \(b\) 为双方的最大数
  • 显然如果 \(a>b\) 那么 A 必然每次都出最大的牌,这样可以必胜,反过来也是一样
  • 于是判断 \(a\) 与 \(b\) 的大小关系即可,\(O(tn)\)

代码

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

const int N = 105;

int n, m1, m2, a[N], b[N];

void work()
{
    read(n); read(m1); read(m2);
    for (int i = 1; i <= m1; i++) read(a[i]);
    for (int i = 1; i <= m2; i++) read(b[i]);
    std::sort(a + 1, a + m1 + 1); std::sort(b + 1, b + m2 + 1);
    puts(a[m1] > b[m2] ? "YES" : "NO");
}

int main()
{
    int T; read(T);
    while (T--) work();
    return 0;
}

B

题意

  • 给定一个 \(n\) 个数的非负整数序列 \(a\),求 \(a\) 的一个子区间使得区间内数的 \(\max\) 和 \(\min\) 之差不小于区间长度,或者告知无解
  • 多组数据,\(\sum n\le2\times10^5\),\(0\le a_i\le10^9\)

做法:线段树+单调栈结论

  • 先判断所有的长度为 \(2\) 的子区间
  • 可以发现如果所有长度为 \(2\) 的子区间的极差都 \(\le 1\) 则一定无解,因为显然 \(n\) 个数的,相邻数之差绝对值不超过 \(1\) 的序列极差的最大值只能是 \(n-1\)(序列单调时取得最大值)
  • \(O(\sum n)\)

代码

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

template <class T>
inline T Abs(const T &a) {return a < 0 ? -a : a;}

const int N = 2e5 + 5;

int n, a[N];

void work()
{
    read(n);
    for (int i = 1; i <= n; i++) read(a[i]);
    for (int i = 1; i < n; i++) if (Abs(a[i] - a[i + 1]) >= 2)
        return (void) printf("YES\n%d %d\n", i, i + 1);
    puts("NO");
}

int main()
{
    int T; read(T);
    while (T--) work();
    return 0;
}

C

题意

  • 给定一个 \(n\) 个数的非负整数序列 \(a\)
  • 给出一种方案,加入不超过 \(3\) 个 \([0,10^{18}]\) 内的数,使得所有数的和是所有数异或和的 \(2\) 倍
  • 可以证明一定存在解
  • 多组数据,\(\sum n\le10^5\),\(0\le a_i\le10^9\)

做法:构造

  • 做法有很多种,这里给出一个加入 \(2\) 个数的方案
  • 设所有数的异或和为 \(x\),所有数的和为 \(s\),则加入的 \(2\) 个数分别为 \(x\) 和 \(x+s\)
  • 这样所有数的异或和为 \(x\bigoplus x\bigoplus (x+s)=x+s\)
  • 所有数的和为 \(s+x+(x+s)=2(x+s)\)
  • 条件得到满足。\(O(\sum n)\)

代码

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

typedef long long ll;

const int N = 1e5 + 5;

int n, a[N];

void work()
{
    ll sum = 0; int xo = 0;
    read(n);
    for (int i = 1; i <= n; i++) read(a[i]), sum += a[i], xo ^= a[i];
    puts("2");
    printf("%d %lld\n", xo, sum + xo);

}

int main()
{
    int T; read(T);
    while (T--) work();
    return 0;
}

D

题意

  • 交互题
  • 有一个 \(k\) 以及一个隐藏的数 \(m\),还有一个 \(n\) 以及一个隐藏的 \(n\) 元序列,保证所有的数互不相同
  • 每次可以询问 \(k\) 个下标,得出序列这些下标上的数中,第 \(m\) 小的数对应的下标
  • 你需要用不超过 \(n\) 次操作询问出 \(m\)
  • \(1\le m\le k<n\le500\),序列的元素在 \([0,10^9]\) 范围内

做法:???(我也不知道叫什么)

  • 认真分析之后发现 \(n\) 是没有用的,只有 \(k<n\) 是有用的,于是我们可以把 \(n\) 当成 \(k+1\)
  • 这样不难发现合法的询问只有 \(k+1\) 种
  • 接下去应该也有很多种做法,这里只说一种
  • 先询问 \(1\dots k\) ,设第 \(m\) 小的数对应下标为 \(x\) ,然后把 \(1\dots k\) 中的 \(x\) 去掉换成 \(k+1\),可以得到 \(x\) 和 \(k+1\) 的大小关系(利用两次询问出的第 \(m\) 小的数值进行判断)
  • 然后依次对于每个 \(i\in[1,k]-\{x\}\),询问 \([1,k]-\{i\}+\{k+1\}\),同样可以得出 \(i\) 和 \(x\) 的大小关系
  • 这样就能得到 \(m\) 的值了,操作次数为 \(k+1\),复杂度 \(O(k^2)\)

代码

#include <bits/stdc++.h>

const int N = 505;

int n, k, pos, val, ans = 1;
bool com;

int main()
{
    int x, y;
    scanf("%d%d", &n, &k);
    printf("? ");
    for (int i = 1; i <= k; i++) printf("%d ", i);
    puts(""); fflush(stdout);
    scanf("%d%d", &pos, &val);
    printf("? ");
    for (int i = 1; i <= k; i++) if (i != pos) printf("%d ", i);
    printf("%d\n", k + 1); fflush(stdout);
    scanf("%d%d", &x, &y); com = y < val;
    for (int i = 1; i <= k; i++) if (i != pos)
    {
        printf("? ");
        for (int j = 1; j <= k; j++) if (j != i) printf("%d ", j);
        printf("%d\n", k + 1); fflush(stdout);
        scanf("%d%d", &x, &y);
        if ((x != pos) ^ com) ans++;
    }
    return printf("! %d\n", ans), 0;
}

E

题意

  • 平面上给定 \(n\) 个互不相同的点,坐标是绝对值不超过 \(10^6\) 的整数
  • 求一种把 \(n\) 个点划分成两个非空集合的方案,使得不存在四个点(可以相同)\(i,j,k,l\) 满足 \(i,j\) 属于同一个集合,\(k,l\) 不属于同一个集合,且 \(i\) 到 \(j\) 的欧几里得距离与 \(k\) 到 \(l\) 的欧几里得距离相等
  • 可以证明一定存在解
  • \(2\le n\le10^3\)

做法:构造

  • 首先发现正三角形无解
  • 从而得出坐标为整数是有用的
  • 看到两个集合又容易想到奇偶性
  • 考虑能否有一种方案,对于两个点 \(i,j\) ,如果距离的平方为偶数则在同一个集合内,否则不在同一个集合内
  • 这启发我们考虑模 \(2\) 意义下的加法。不难发现把两维坐标之和为奇数的放一个集合,偶数的放另一个集合可以满足条件
  • 如果两维坐标之和的奇偶性全相同怎么办?
  • 发现在这种情况下,把坐标系旋转 \(45\) 度并把坐标压缩到 \(\frac 1{\sqrt 2}\) 之后,所有的点坐标仍然是整数
  • 于是这样处理之后继续做
  • 每旋转一次之后任意两点之间的距离的平方都会除以 \(2\),所以复杂度 \(O(n\log d)\),\(d\) 为任意两点之间最小距离

代码

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

const int N = 1005;

int n, m, X[N], Y[N];

int main()
{
    read(n);
    for (int i = 1; i <= n; i++) read(X[i]), read(Y[i]);
    while (1)
    {
        int c0 = 0, c1 = 0;
        for (int i = 1; i <= n; i++)
            (X[i] + Y[i] & 1 ? c1 : c0)++;
        if (c0 && c1)
        {
            std::cout << c1 << std::endl;
            for (int i = 1; i <= n; i++) if (X[i] + Y[i] & 1)
                printf("%d ", i);
            return puts(""), 0;
        }
        for (int i = 1; i <= n; i++)
        {
            int x = X[i] + Y[i], y = X[i] - Y[i];
            X[i] = x - (c1 > 0) >> 1; Y[i] = y - (c1 > 0) >> 1;
        }
    }
    return 0;
}

F

题意

  • 给定一个 \(01\) 序列 \(s\)
  • 求有多少个子区间满足其包含至少一个 \(1\),并且 \(1\) 的个数是区间长度的约数
  • \(1\le |s|\le 2\times10^5\)
  • 时限 8s

做法:根号分治

  • 这题没开感觉十分亏
  • 第一部分:如何求 \(1\) 的个数不超过 \(S\) 的合法子区间数
  • 先枚举右端点,再枚举 \(1\le i\le S\) 表示 \(1\) 的个数
  • 显然右端点固定下来之后,满足区间内 \(1\) 的个数恰好为 \(i\) 的子区间的左端点是连续的一段
  • 于是这时产生的区间内 \(1\) 的个数恰好为 \(i\) 的子区间的长度也是连续的一段,设其为 \([u,v]\)
  • 那么要计入答案的就是 \([u,v]\) 内 \(i\) 的倍数的个数,即 \(\lfloor\frac vi\rfloor-\lfloor\frac{u-1}i\rfloor\)
  • \(O(nS)\)
  • 第二部分:如何求 \(\frac{len}{cnt}\) 不超过 \(S\) 的合法子区间数,\(len\) 为区间长度,\(cnt\) 为 \(1\) 的个数
  • 还是枚举 \(1\le\frac{len}{cnt}=i\le S\)
  • 考虑先给每个数一个权值 \(a_x=1-[s_x=1]\times i\)
  • 易得一个子区间的 \(\frac{len}{cnt}=i\) 当且仅当该区间的 \(a\) 之和为 \(0\)
  • 于是求出 \(a\) 有多少对相同的前缀和即可
  • \(O(nS\log S)\)(sort)或 \(O(nS)\)(利用上哈希或 std::unordered_map
  • 考虑把这两部分暴力结合起来
  • 易得对于一个合法区间,其 \(cnt\) 和 \(\frac{len}{cnt}\) 不可能同时超过 \(\sqrt n\)
  • 于是取 \(S=\lfloor\sqrt n\rfloor\),跑一遍第二种暴力
  • 然后再跑第一种暴力,注意直接算则会把 \(cnt\) 和 \(\frac{len}{cnt}\) 都不超过 \(S\) 的子区间算重,需要限制长度不小于 \((i+1)S\)
  • \(O(n\sqrt n)\)

代码

#include <bits/stdc++.h>

typedef long long ll;

const int N = 2e5 + 5;

int n, S, a[N], top, stk[N];
ll ans, sum[N];
char s[N];

int main()
{
    scanf("%s", s + 1); n = strlen(s + 1);
    S = sqrt(n);
    for (int d = 1; d <= S; d++)
    {
        for (int i = 1; i <= n; i++) a[i] = 1 - (s[i] == '1' ? d : 0);
        sum[0] = 0;
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
        std::sort(sum, sum + n + 1);
        for (int i = 0; i <= n;)
        {
            int j = i;
            while (j <= n && sum[i] == sum[j]) j++;
            ans += 1ll * (j - i) * (j - i - 1) >> 1;
            i = j;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (s[i] == '1') stk[++top] = i;
        for (int j = 1; j <= S && j <= top; j++)
        {
            int l = i - stk[top - j + 1] + 1, r = i - stk[top - j];
            if (l < j * (S + 1)) l = j * (S + 1);
            if (l > r) continue;
            ans += r / j - (l - 1) / j;
        }
    }
    return std::cout << ans << std::endl, 0;
}

G

题意

  • 给定 \(n\) 个整数 \(a_{1\dots n}\),对于每个 \(i\) 都满足 \(i-n\le a_i\le i-1\)
  • 求这 \(n\) 个整数中选出一个非空子集使得和为 \(0\)
  • \(1\le n\le 10^6\)

做法:构造

  • 妙啊!!!\(\times 1\)(不过听说随机乱搞能过???)
  • 首先 \(i-n\le a_i\le i-1\) 相当于 \(1\le i-a_i\le n\)
  • 考虑建立图论模型:\(i\) 向 \(i-a_i\) 连一条边,显然这是一个基环树森林
  • 考虑一个环,易得如果选出的子集为这个环上的点,环上每条边的贡献都是入点与出点的编号差,于是和为 \(0\)
  • 于是随便找一个环即可,\(O(n)\)

代码

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

const int N = 1e6 + 5;

int n, a[N], cnt;
bool vis[N];

void work()
{
    int u;
    read(n); cnt = 0;
    for (int i = 1; i <= n; i++) read(a[i]), a[i] = i - a[i];
    for (int i = 1; i <= n; i++) vis[i] = 0;
    for (u = 1; !vis[u]; u = a[u]) vis[u] = 1;
    for (int i = 1; i <= n; i++) vis[i] = 0;
    for (; !vis[u]; u = a[u]) vis[u] = 1, cnt++;
    for (int i = 1; i <= n; i++) vis[i] = 0;
    printf("%d\n", cnt);
    for (; !vis[u]; u = a[u]) vis[u] = 1, printf("%d ", u);
    puts("");
}

int main()
{
    int T; read(T);
    while (T--) work();
    return 0;
}

H

题意

  • 给定 \(n\) 个数 \(a_{1\dots n}\),每个数都是不超过 \(10^6\) 的正整数
  • 对于任意 \(1\le i<j\le n\),如果 \(a_i<a_j\) 则连边 \((i,j)\),求连通块数
  • 有 \(q\) 次单点修改,你需要在每次修改之后输出上面问题的答案,保证任何时候这 \(n\) 个数互不相同
  • \(1\le n,q\le 5\times10^5\)
  • 时限 8s

做法:线段树维护连续段

  • 性质:每个连通块都是一段区间,且任意连通块内数的 \(\min\) 都大于下一个连通块内数的 \(\max\)
  • 证明略
  • 问题转化成有多少个 \(1\le i\le n\) 满足对于任意 \(j\le i,k>i\) 都有 \(a_j>a_k\)
  • 即整个序列前 \(i\) 大的数恰好占据了序列前 \(i\) 个位置
  • 考虑暴力,把所有的数从大到小插入
  • 易得组成恰好一个前缀连通块的条件为不存在 \(1\le i<n\) 使得 \(i\) 位置还没被插入,\(i+1\) 位置已经被插入
  • 于是考虑开一棵值域为 \([1,10^6]\) 的线段树,位置 \(h\) 储存插入了所有 \(\ge h\) 的数之后满足如上条件的 \(i\) 个数,并维护区间最小值及最小值个数
  • 对于所有 \(a_i<a_{i+1}\),我们让线段树的区间 \([a_i+1,a_{i+1}]\) 加一
  • 这样答案就是全体最小值的个数(如果最小值不为 \(0\) 则答案为 \(0\))
  • 修改时讨论 \(pos-1,pos,pos+1\) 三个位置的影响并重新进行区间加即可
  • 但上面的过程中忽略了一个条件,如果 \(h\) 不与任意的 \(a_i\) 相等,那么这样的 \(h\) 是不能计入答案的,所以实现时我们还要记录区间内有多少个 \(h\) 是能够计入答案的,每次修改时要对这个东西进行单点修改
  • \(O((n+q)\log a)\)

代码

#include <bits/stdc++.h>
#define p2 p << 1
#define p3 p << 1 | 1

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

const int N = 5e5 + 5, M = 4e6 + 17, L = 1e6;

int n, q, a[N], add[M], pts[M];
bool is[M];

struct elem
{
    int val, cnt;

    friend inline elem operator + (elem a, elem b)
    {
        if (a.val < b.val) return a;
        else if (a.val > b.val) return b;
        return (elem) {a.val, a.cnt + b.cnt};
    }
} T[M];

void build(int l, int r, int p)
{
    T[p].val = add[p] = 0;
    if (l == r) return (void) (T[p].cnt = pts[p] = is[l]);
    int mid = l + r >> 1;
    build(l, mid, p2); build(mid + 1, r, p3);
    T[p].cnt = pts[p] = pts[p2] + pts[p3];
}

void down(int p)
{
    add[p2] += add[p]; add[p3] += add[p];
    T[p2].val += add[p]; T[p3].val += add[p];
    add[p] = 0;
}

void modify(int l, int r, int pos, int v, int p)
{
    if (l == r) return (void) (pts[p] += v, T[p].cnt += v);
    int mid = l + r >> 1; down(p);
    if (pos <= mid) modify(l, mid, pos, v, p2);
    else modify(mid + 1, r, pos, v, p3);
    T[p] = T[p2] + T[p3];
}

void change(int l, int r, int s, int e, int v, int p)
{
    if (e < l || s > r) return;
    if (s <= l && r <= e) return (void) (add[p] += v, T[p].val += v);
    int mid = l + r >> 1; down(p);
    change(l, mid, s, e, v, p2); change(mid + 1, r, s, e, v, p3);
    T[p] = T[p2] + T[p3];
}

elem ask(int l, int r, int s, int e, int p)
{
    if (e < l || s > r) return (elem) {-1, 0};
    if (s <= l && r <= e) return T[p];
    int mid = l + r >> 1; down(p);
    return ask(l, mid, s, e, p2) + ask(mid + 1, r, s, e, p3);
}

int main()
{
    int pos, x; read(n); read(q);
    for (int i = 1; i <= n; i++) read(a[i]), is[a[i]] = 1;
    build(1, L, 1);
    for (int i = 1; i < n; i++) if (a[i] < a[i + 1])
        change(1, L, a[i] + 1, a[i + 1], 1, 1);
    while (q--)
    {
        read(pos); read(x);
        modify(1, L, a[pos], -1, 1); modify(1, L, x, 1, 1);
        if (pos > 1)
        {
            if (a[pos - 1] < a[pos]) change(1, L, a[pos - 1] + 1, a[pos], -1, 1);
            if (a[pos - 1] < x) change(1, L, a[pos - 1] + 1, x, 1, 1);
        }
        if (pos < n)
        {
            if (a[pos] < a[pos + 1]) change(1, L, a[pos] + 1, a[pos + 1], -1, 1);
            if (x < a[pos + 1]) change(1, L, x + 1, a[pos + 1], 1, 1);
        }
        a[pos] = x; printf("%d\n", T[1].val ? 0 : T[1].cnt);
    }
    return 0;
}

I

题意

  • 给定一个 \(2^k\times 2^k\) 的正整数矩阵 \(a\),每个数在 \([0,2^{60})\) 内,行列从 \(0\) 开始标号
  • 还有一个大小为 \(t\) 的二元组集合 \(S=\{(x,y)\}\),里面的元素互不相同且 \(1\le x,y\le 2^k\)
  • 每次操作可以选择一个位置 \((u,v)\) 和一个数 \(p\),对于每个 \((x,y)\in S\),让矩阵 \(((u+x)\bmod 2^k,(v+y)\bmod 2^k)\) 位置上的数异或上 \(p\)
  • 求把所有的数都变成 \(0\) 的最少操作次数
  • \(1\le k\le 9,1\le t\le\min(99,4^k)\) 且 \(t\) 是奇数
  • 时限 5s

做法:异或 + 分治

  • 妙啊!!!\(\times 2\)
  • 为了方便讨论,先把二元组集合内的横纵坐标都减一
  • 设数组 \(f_{i,j}=\sum_{(x,y)\in S}a_{(i-x)\bmod2^k,(j-y)\bmod2^k}\)
  • 性质 \(1\):当 \(t\) 为奇数时,\(a\) 全 \(0\) 当且仅当 \(f\) 全 \(0\)
  • 证明咕咕咕(我还没看),可以看原题解
  • 性质 \(2\):对 \((i,j)\) 进行异或 \(p\) 操作的影响是对于每个 \((x,y)\in S\) 使 \(f_{(i+2x)\bmod2^k,(j+2y)\bmod2^k}\) 异或上 \(p\)
  • 首先直观地描述,对 \((i,j)\) 进行异或 \(p\) 操作相当于在 \(S\) 中分两次,每次选一个二元组,设这两个二元组分别为 \((x,y)\) 和 \((u,v)\),让 \(f_{(i+x+u)\bmod2^k,(j+y+v)\bmod2^k}\) 异或上 \(p\)
  • 若 \((x,y)\ne(u,v)\),则两次分别选出 \((x,y)(u,v)\) 和分别选出 \((u,v)(x,y)\) 的影响是一样的,根据异或运算的性质 \(p\bigotimes p=0\),可以得到如果 \((x,y)\ne(u,v)\) 的情况不造成影响
  • 于是只剩下了 \((x,y)=(u,v)\) 的情况,\(\text{Q.E.D.}\)
  • 观察性质 \(2\),容易发现如果把矩阵 \(f\) 按照行列号的奇偶性拆成 \(4\) 个部分,那么每个部分是独立的,可以分别递归做
  • 递归到 \(k=0\) 的时候判断矩阵的唯一元素是否为 \(0\) 即可计入答案
  • \(O(4^kkt)\)
  • 异或真的是最美妙的运算啊。

代码

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

typedef long long ll;
typedef std::vector<std::pair<int, int> > vp;
typedef std::vector<ll> vl;
typedef std::vector<vl> vvl;

const int N = 520;

int k, t, ans;
vl emp;
vvl a;
vp op;

vvl trans(vvl a, vp op)
{
    int n = a.size();
    vvl res;
    for (int i = 0; i < n; i++)
    {
        res.push_back(emp);
        for (int j = 0; j < n; j++)
        {
            res[i].push_back(0);
            for (int k = 0; k < t; k++)
                res[i][j] ^= a[i - op[k].first + n & n - 1]
                    [j - op[k].second + n & n - 1];
        }
    }
    return res;
}

void jjd(vvl a, vp op)
{
    if (a.size() == 1) return (void) (ans += (a[0][0] > 0));
    a = trans(a, op); int n = a.size();
    vvl b[2][2];
    for (int i = 0; i < n; i++)
    {
        b[i & 1][0].push_back(emp); b[i & 1][1].push_back(emp);
        for (int j = 0; j < n; j++)
            b[i & 1][j & 1][i >> 1].push_back(a[i][j]);
    }
    for (int i = 0; i < t; i++) op[i].first &= (n >> 1) - 1,
        op[i].second &= (n >> 1) - 1;
    for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++)
        jjd(b[i][j], op);
}

int main()
{
    read(k); ll x; int u, v;
    for (int i = 0; i < (1 << k); i++)
    {
        a.push_back(emp);
        for (int j = 0; j < (1 << k); j++)
            read(x), a[i].push_back(x);
    }
    read(t);
    for (int i = 1; i <= t; i++)
        read(u), read(v), op.push_back(std::make_pair(u - 1, v - 1));
    return std::cout << (jjd(a, op), ans) << std::endl, 0;
}

原文地址:https://www.cnblogs.com/xyz32768/p/12147147.html

时间: 2024-10-07 17:00:23

[题解][Codeforces]Good Bye 2019 简要题解的相关文章

【题解】CF616(Div 2)简要题解

[题解]CF616(Div 2)简要题解 A 分类讨论 若数码和是奇数 若最后一个数是奇数:找到从前往后第一个奇数数位删掉 若最后一个数是偶数:不断删除最后一个数直到这个剩下的数是奇数,由于之前删掉的数都是偶数所以对数码和\(\mod 2\)不会有影响.再做一遍第一个算法即可. 若数码和是偶数 若最后一个数是奇数:符合条件 若最后一个数是偶数:不断删除最后一个数直到奇数.由于之前删掉的数都是偶数所以对数码和\(\mod 2\)不会有影响,直接输出即可. 最后要判断一下前导零. B 可以发现若有合

Educational Codeforces Round 80 A-E简要题解

contest链接:https://codeforces.com/contest/1288 A. Deadline 题意:略 思路:根据题意 x + [d/(x+1)] 需要找到一个x使得上式小于等于n,即x + [d/(x+1) ] <=n,不等式两边同时+1得 x+1 + [d/(x+1)] <=n + 1当且仅当(x+1)2 = d时,式子左边最小,所有只需要判断一下最小值是否<=n+1就可以知道该不等式是否存在x满足题意了,即找到x = √d - 1,判断一下即可. AC代码:

Atcoder Yahoo Programming Contest 2019 简要题解

A-C 直接放代码吧. A int n,k; int main() { n=read();k=read(); puts(k<=(n+1)/2?"YES":"NO"); return 0; } B int d[N];pair<int,int>s[10]; int main() { for(int i=1,u,v;i<=3;i++){ u=read();v=read(); s[i].first=u;s[i].second=v; d[u]++;d[

杂题记录及简要题解(三)

以下是大概 5 月初开始做的一些题.以前的简要题解都是骗人的.这次真的是简要题解了(大雾 相对之前改良了一下题目名称的格式. 2017 计蒜之道 初赛 - 腾讯狼人杀 二分答案 \(x\) 后原问题变为检验是否存在选取方案 \((V, E)(|V| = k)\) 使得 \(\sum_\limits{e \in E} w_e - xk \cdot (2n- k)\).式子可以写成 \(\sum_\limits{e \in E} w_e + \frac{k(k - 1)}{2} \cdot 2x -

Codeforces A. Valera and X 题解

判断二维字符串是否满足下面条件: on both diagonals of the square paper all letters are the same; all other squares of the paper (they are not on the diagonals) contain the same letter that is different from the letters on the diagonals. Help Valera, write the progra

Codeforces Round #262 (Div. 2) 题解

A. Vasya and Socks time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya has n pairs of socks. In the morning of each day Vasya has to put on a pair of socks before he goes to school. When

codeforces A. Shaass and Oskols 题解

Shaass has decided to hunt some birds. There are n horizontal electricity wires aligned parallel to each other. Wires are numbered 1 to n from top to bottom. On each wire there are some oskols sitting next to each other. Oskol is the name of a delici

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

Codeforces D. Giving Awards 412 题解

就是按照一定顺序输出排序. 比如a欠b的钱就不能先输出a然后输出b. 本题的技巧就是,要求的是不能先输出a然后输出b,但是可以先输出b然后输出a. 故此可以按照a欠b的钱的关系,建立图,然后DFS深度优先搜索,然后逆向记录点,输出这些逆向点,也就是a欠b的钱,就先输出b然后输出a,那么这个顺序就满足要求了. 很狡猾的题意.要细心.不然就搞半天都白搞了. 题目连接:http://codeforces.com/problemset/problem/412/D #include <stdio.h>