洛谷 P9915 「RiOI-03」3-2 题解

Preface

为啥有蓝啊,这题在机房里 15min 左右就切了,反倒是 2A 做了 1h。。

Solution

将矩阵逆时针旋转 \(90^{\circ}\),你会发现这是一棵线段树,是父亲左儿子的节点颜色是 \(0\),是右儿子的节点颜色是 \(1\)

容易发现,联通块一定是一条链。具体地,你从给定的点向上跳,跳到第一个与自己异色的点,然后从这个点一路向下联通,可以联通到叶子。

我们令叶子那层是第 \(0\) 层,那么如果向上跳到的点深度为 \(d\),答案就是 \(\sum_{i=0}^{d}2^i=2^{d+1}-1\)

判断 \(y\) 是否超出了 \(x\) 的最高位,如果是,说明能联通到根,答案为 \(2^n-1\);否则暴力向上跳即可。

时间复杂度 \(\mathcal{O}(q\log n)\)

Code

#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define pb push_back
using namespace std;
namespace Milkcat {
    typedef long long LL;
    typedef pair<LL, LL> pii;
    const int N = 1e6 + 5, mod = 998244353;
    LL n, q, x, y;
    LL qpow(LL b, LL k) { LL r = 1; for (; k; b = b * b % mod, k >>= 1) if (k & 1) r = r * b % mod; return r; }
    int main() {
		cin >> n >> q;
		REP(test, 1, q) {
			cin >> x >> y;
			if (__lg(x) < y) {
				cout << (qpow(2, n) - 1 + mod) % mod << '\n';
			} else {
				int p = x >> y & 1;
				while ((x >> y & 1) == p) y ++;
				cout << (qpow(2, y) - 1 + mod) % mod << '\n';
			}
		}
        return 0;
    }
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int T = 1;
    while (T --) Milkcat::main();
    return 0;
}
posted @ 2024-01-19 19:04  喵仔牛奶  阅读(37)  评论(0)    收藏  举报