T1
给 \(m\) 个质数,第 \(i\) 个质数 \(p_i\) 出现了 \(n_i\) 次。求一种划分质数的方案,使得第一个集合的和等于第二个集合的乘积。
萌萌题,注意到最后相当于是要求 \(p_1^{\alpha_1}p_2^{\alpha_2}\cdots p_k^{\alpha_k}+\alpha_1p_1+\alpha_2p_2+\cdots+\alpha_kp_k=\sum n_ip_i\),发现 \(\sum n_ip_i-\sum \alpha_ip_i\) 的可能的取值范围只有 \([sum-\log V, V]\),直接枚举这个数然后质因数分解即可。
T2
给出 \(m\) 个限制,限制形如 \(x_a-x_b=c\pmod d\),问每个限制是否与之前的限制冲突。
这个题比较神,考场上没想出来。可以开 \(\log V\) 个带权并查集,第 \(i\) 个并查集上两个点 \(a,b\) 之间的距离代表 \(x_a-x_b \bmod 2^i\),来一个新限制的时候先检查是否与之前的限制重复了,如果重复就判断是否合法,不重复就直接添加。
这个的正确性可以这么想:\(d\) 大的限制会给更小的 \(d'<d\) 另一个限制 \((c\bmod d', d')\),然后一个新的限制 \((c,d)\) 只要满足所有 \(d'<d\) 的 \((c',d')\) 的限制就会合法。
考场上想要把这个东西离线下来建出树来做树剖,但是发现每个位上的树形态可能不一样,遂倒闭。
const int MAXN = 5e5 + 5, MAXV = 32;
int n, m;struct _dsu {int fa[MAXN], dis[MAXN];void merge(int x, int y, int w) {fa[x] = y;dis[x] = w;}int find(int x) {if (fa[x] == x) return x;int f = find(fa[x]);dis[x] += dis[fa[x]];fa[x] = f;return f;}void init() {for (int i = 1; i <= n; ++i)fa[i] = i;}
} dsu[MAXV + 1];int f(int x, int d) {return (x % (1ll << d) + (1ll << d)) % (1ll << d);
}void work() {cin >> n >> m;for (int i = 0; i <= MAXV; ++i)dsu[i].init();for (int i = 1; i <= m; ++i) {int a, b, c, d;cin >> a >> b >> c >> d;if (d == -1) d = MAXV;else {if (d == 1) d = 0;else d = __lg(d);}bool flg = true;for (int i = 0; i <= d; ++i) {if (dsu[i].find(a) != dsu[i].find(b)) continue;if (f(dsu[i].dis[a] - dsu[i].dis[b], i) == f(c, i))continue;flg = false; break;}if (flg == false) {cout << 0 << endl;continue;}for (int i = 0; i <= d; ++i) {if (dsu[i].find(a) == dsu[i].find(b)) continue;int da = dsu[i].dis[a], db = dsu[i].dis[b];dsu[i].merge(dsu[i].find(a), dsu[i].find(b), f(c - da + db, i));}cout << 1 << endl;}
}
T3/T4
可能不会补了。