LY1363 [ 20231005 NOIP 模拟赛 T3 ] 环游世界
题意
给定 \(m\) 个限制为 \(l_i\) 到 \(r_i\) 的异或和为 \(s_i\)。
求序列可能的方案数。
Sol
看到异或可以考虑拆位,手玩一下发现本题拆位是没法做的。
看到区间限制,考虑做前缀异或和变成对于 \(l_i - 1\) 和 \(r_i\) 两个点做限制。
显然每个前缀异或和的序列与原序列一一对应,只要求出前缀异或和序列的方案数即可。
考虑判不合法,注意到每个联通块会形成若干个环,考虑暴力赋值判断,这显然是 trivial 的。
这道题就做完了。
Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <bitset>
#define int long long
#define pii pair <int, int>
using namespace std;
#ifdef ONLINE_JUDGE
/* #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) */
/* char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; */
#endif
int read() {
int p = 0, flg = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') flg = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
p = p * 10 + c - '0';
c = getchar();
}
return p * flg;
}
void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
#define fi first
#define se second
const int N = 1e5 + 5, M = 2e5 + 5, mod = 998244353;
array <int, N> isl;
namespace G {
array <int, N> fir;
array <int, M> nex, to, len;
int cnt;
void add(int x, int y, int z) {
cnt++;
nex[cnt] = fir[x];
to[cnt] = y;
len[cnt] = z;
fir[x] = cnt;
}
}
/*
namespace Uni {
array <int, N> fa, siz;
void init() {
for (int i = 1; i <= 1e5 + 2; i++)
siz[fa[i] = i] = 1;
}
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void merge(int x, int y) {
int fx = find(x),
fy = find(y);
if (fx == fy) return;
if (siz[fx] > siz[fy]) swap(fx, fy);
fa[siz[fx]] = fy;
siz[fy] += siz[fx];
}
}
*/
array <pii, N> qrl;
array <int, N> dis;
bitset <N> vis;
using namespace G;
bool dfs(int x) {
vis[x] = 1;
bool ans = 1;
for (int i = fir[x]; i; i = nex[i]) {
if (!vis[to[i]])
dis[to[i]] = (dis[x] ^ len[i]), ans &= dfs(to[i]);
else if (vis[to[i]] && dis[to[i]] != (dis[x] ^ len[i]))
return false;
}
return ans;
}
int pow_(int x, int k, int p) {
int ans = 1;
while (k) {
if (k & 1) ans = ans * x % p;
x = x * x % p;
k >>= 1;
}
return ans;
}
signed main() {
int n = read(), k = read(), m = read();
for (int i = 1; i <= m; i++) {
int l = read(), r = read();
isl[i] = read();
qrl[i].fi = l - 1, qrl[i].se = r;
G::add(l - 1, r, isl[i]);
G::add(r, l - 1, isl[i]);
}
int ans = 0;
dis.fill(-1);
for (int i = 0; i <= n; i++) {
if (vis[i]) continue;
ans++;
if (!dfs(i)) return puts("0"), 0;
}
write(pow_(pow_(2, k, mod), ans - 1, mod)), puts("");
return 0;
}