T1. 反转

枚举反转了多少行和列(因为行和行之间本身没有区别,列同理),算一下是否有 \(k\) 个格子被反转。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    
    rep(i, n+1) {
        rep(j, m+1) {
            if (i*j + (n-i)*(m-j) == k) {
                puts("Yes");
                return;
            }
        }
    }
    
    puts("No");
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

T2. 函数

请注意,该序列是循环的,意味着序列的形式如下:

\[[a, b, a \oplus b, a, b, a \oplus b, \cdots] \]

我们几乎可以通过确定循环节来完成整个任务。循环节个数是 \(3\) 个整数组成的段数。区间长度是 \(r-l+1\),因此循环节个数为 \(\lfloor\frac{r-l+1}{3}\rfloor\)

我们通过注意到循环从区间第一个 \(a\) 开始,最后一个 \(a \oplus b\) 结束,来获取循环开始和结束下标。除此之外,我们再来求剩余的元素(最多 \(2\) 个)的和,循环部分的和为:

\[\lfloor\frac{r-l+1}{3}\rfloor \times (a + b + a \oplus b) \]

总复杂度为 \(O(n)\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

void solve() {
    int a, b, l, r;
    cin >> a >> b >> l >> r;
    --l; --r;
    
    vector<int> x(3);
    x[0] = a;
    x[1] = b;
    x[2] = a^b;
    
    ll sum = 0;
    rep(i, 3) sum += x[i];
    
    int n = r-l+1;
    int si = l%3;
    ll ans = n/3*sum;
    n %= 3;
    rep(i, n) ans += x[(si+i)%3];
    
    cout << ans << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

T3. 电管

显然红蓝绿对应 \(0 \sim 2\) 三种数。考虑构造一种运算符,发现 \(a \oplus b = -(a+b)\) 是合理的。
然后考虑 \(a_i\)\(a_{i-d}\) 的贡献。注意到构造的运算符对 \(a_i\) 的贡献大概长 \(a_i = -(a_i + a_{i+1})\),说明按一次开关,\(a_i\) 会对 \(a_{i-1}\)\(a_i\) 造成一次贡献。推广到按下 \(m\) 次开关的情况,其中 \(a_i\)\(a_{i-d}\) 的贡献为 \(\binom{m}{d}\) 。注意到我们最终的答案要对 \(3\) 取模,考虑 \(\text{Lucas}\) 定理。

注意到一个现实意义是,我们按 \(a+b\) 次,和先按 \(a\) 次,再按 \(b\) 次的结果是一样的,我们考虑将 \(m\) 三进制分解,每次只取出一个 \(3^x\),这样 \(d\) 只有为 \(0\)\(3^x\) 时,才会产生贡献,且系数为 \(1\) 。可以直接暴力做,时间复杂度为 \(O(n\log m)\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n; ll m;
    string s;
    cin >> n >> m >> s;
    
    vector<int> a(n);
    rep(i, n) {
        if (s[i] == 'r') a[i] = 0;
        if (s[i] == 'g') a[i] = 1;
        if (s[i] == 'b') a[i] = 2;
    }
    
    ll x = m;
    ll t = 1;
    while (x) {
        for (int ri = 1; ri <= x%3; ++ri) {
            vector<int> b(n);
            rep(i, n) b[i] = (a[i]+a[(i+t)%n])%3;
            rep(i, n) a[i] = b[i];
        }
        t *= 3;
        x /= 3;
    }
    
    if (m&1) {
        rep(i, n) a[i] = (3-a[i])%3;
    }
    
    string ans;
    rep(i, n) {
        if (a[i] == 0) ans += 'r';
        if (a[i] == 1) ans += 'g';
        if (a[i] == 2) ans += 'b';
    }
    
    cout << ans << '\n';
    
    return 0;
}

T4. 柚子

原题:惊蛰