OIFC 2025.11.21 模拟赛总结
快考 NOIP 了。
T1 构造题
题目描述
给定一个正整数 \(n\),请构造一个长度为 \(n\) 的排列 \(p\),满足 \(\forall i \in [1, n - 1]\),\(p_i \oplus p_{i + 1}\) 不是质数,或报告无解。
数据范围:\(1 \leq \sum n \leq 5 \times 10^6\),\(1 \leq T \leq 10^5\)。
题解
如果两个数模 \(4\) 同余,则其二进制最后两位是一样的,因此这两个数异或结果是 \(4\) 的倍数!
因此,我们可以把 \(1 \sim n\) 分成 \(4\) 类,只需考虑如何合并这 \(4\) 类。
先说结论:假设 \(P_r(n)\) 表示 \([1, n]\) 中 \(\bmod 4 = r\) 的数从小到大排序得到的序列,则构造:
合法。其中 \(rev\) 表示把整个序列翻转,即倒序。
简单证明一下:对于第一个 \(+\),显然 \(1\) 和大奇数异或是大偶数;对于第二个 \(+\),显然 \(3 \oplus 2 = 1\);对于第三个 \(+\),两个偶数异或一定得到偶数,而且当 \(n\) 足够大的时候,异或结果一定大于 \(2\),所以这样构造在 \(n\) 比较大的时候是正确的。
简单尝试一下,可以发现 \(n \geq 10\) 的时候可以直接这样构造。对于 \(n < 10\) 的情况,直接跑 dfs 暴搜即可。
参考代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void write(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
signed main(){
freopen("constructive.in", "r", stdin);
freopen("constructive.out", "w", stdout);
int T = read();
while(T--){
int n = read();
if(n < 10){
if(n == 1) puts("1");
if(n == 2) puts("-1");
if(n == 3) puts("-1");
if(n == 4) puts("-1");
if(n == 5) puts("1 5 3 2 4");
if(n == 6) puts("-1");
if(n == 7) puts("1 5 3 7 6 2 4");
if(n == 8) puts("1 5 3 2 4 8 6 7");
if(n == 9) puts("4 2 6 7 3 5 1 8 9");
continue;
}
for(int i = n; i >= 1; i--) if(i % 4 == 1) write(i), putchar(' ');
for(int i = n; i >= 1; i--) if(i % 4 == 3) write(i), putchar(' ');
for(int i = 1; i <= n; i++) if(i % 4 == 2) write(i), putchar(' ');
for(int i = 1; i <= n; i++) if(i % 4 == 0) write(i), putchar(' ');
putchar('\n');
}
return 0;
}
T2 解方程
题目描述
有长为 \(N\) 的整数数列 \(A = (A_1, A_2, \cdots, A_N)\),但是并未给出数列 \(A\) 的具体值。
给定 \(Q\) 个关于整数数列 \(A\) 的事件。第 \(i\) 个 \((1 \leq i \leq Q)\) 事件由 \(4\) 个整数 \(T_i,X_i,Y_i,V_i\) 表示。
-
\(T_i = 0\) 表示给出 \(A_{X_i} + A_{Y_i} = V_i\)。
-
\(T_i = 1\) 表示当 \(A_{X_i} = V_i\) 时,询问 \(A_{Y_i}\) 的值。
注意询问之间是相互独立的。
请依次处理事件并回答每个询问。如果询问的时候 \(A_{Y_i}\) 的值无法确定,输出 Ambiguous 回答询问,如果询问的时候没有任何满足所有条件的长为 \(N\) 的整数数列 \(A\),输出 Impossible 回答询问。
本题单个测试点内有多组测试数据,并且可能会要求强制在线。
输入格式
从文件 equation.in 中读入数据。
第一行三个用一个空格分隔的整数 \(C, M, W\) 分别表示测试数据组数、强制在选参数以及 \(V_i\) 的值域。
对于每组测试数据:
第一行一个正整数 \(N\)。
第二行一个正整数 \(Q\)。
接下来 \(Q\) 行,每行四个用一个空格分隔的整数,其中第 \(i\) 行分别为 \(T_i', X_i', Y_i, V_i'\)。
有强制在线参数 \(L\),若本组测试数据尚未产生输出,则 \(L = 0\),否则,若上一次询问输出了 Ambiguous,则 \(L = 123456797654321\),否则,若上一次询问输出了 Impossible,则 \(L = 976543212345679\),否则,记上一次询问输出的数字为 \(l\),则 \(L = l + 515472268187439\),可以证明 \(L\) 总是大于等于 \(0\) 的整数。
在每次询问完成后以及每组测试数据开始前都需要对 \(L\) 进行重新计算。
对于第 \(i\) 个事件:
-
\(T_i = (T_i' + M \times L) \bmod 2\)。
-
\(X_i = (X_i' - 1 + M \times L) \bmod N + 1\)。
-
\(Y_i = (Y_i' - 1 + M \times L) \bmod N + 1\)。
-
\(V_i = (V_i' + M \times L) \bmod (w + 1)\)。
输出格式
输出到文件 equation.out 中。
对于每组测试数据:
每组询问输出一行,表示该组询问的答案。如果 \(A_{Y_i}\) 的值无法确定,输出 Ambiguous,如果没有任何满足所有条件的数列 \(A\),输出 Impossible。
样例
Input 1
2 0 5
4
5
0 1 2 3
1 1 2 1
0 3 4 0
1 4 2 5
1 4 4 3
5
5
0 1 2 3
0 3 4 1
1 5 5 2
0 1 4 5
1 3 2 3
Output 1
2
Ambiguous
3
2
-4
Input 2
2 1 5
4
5
0 1 2 3
1 1 2 1
1 2 3 1
0 3 1 0
0 3 3 4
5
5
0 1 2 3
0 3 4 1
1 5 5 2
1 5 3 0
0 2 1 4
Output 2
2
Ambiguous
3
2
-4
数据范围
对于所有数据满足:
-
\(1 \leq C \leq 20\)。
-
\(M \in \{0, 1\}\)。
-
\(0 \leq W \leq 2 \times 10^9\)。
-
\(1 \leq N \leq 10^5\)。
-
\(1 \leq Q \leq 10^5\)。
-
\(T_i' \in \{0, 1\}(1 \leq i \leq Q)\)。
-
\(T_i \in \{0, 1\}(1 \leq i \leq Q)\)。
-
\(1 \leq X_i', Y_i' \leq N(1 \leq i \leq Q)\)。
-
\(1 \leq X_i, Y_i \leq N(1 \leq i \leq Q)\)。
-
\(0 \leq V_i' \leq W(1 \leq i \leq Q)\)。
-
\(0 \leq V_i \leq W(1 \leq i \leq Q)\)。
-
输入的数字全部为整数。
本题不采用捆绑测试。
题解
考虑使用并查集维护。
考虑记录一个数组,表示是否知道一个点的具体值。如果不知道,则记录其与并查集根节点的差。
我们使用拓展域并查集维护边权信息,另外还需要维护路径的奇偶性。此时加边就可以直接加,查询就可以直接查。
如果出现了合法的奇环,只需将连通块的根附上权值就可以高效地维护了。
参考代码:
#include<bits/stdc++.h>
#define int long long
#define mset(a) memset(a, 0, sizeof(a))
using namespace std;
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)){
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)){
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void write(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
return;
}
int T, M, W, n, q, fa[100005], sz[100005], L, isknown[100005], val[100005], dep[100005];
bool bad = false;
vector<pair<int, int> > e[100005];
const int Ambiguous = 123456797654321ll, Impossible = 976543212345679ll, Normal = 515472268187439ll;
inline int find(int k){
if(fa[k] == k) return k;
return fa[k] = find(fa[k]);
}
inline void clear(){
L = 0;
n = read(), q = read();
for(int i = 1; i <= n; i++) fa[i] = i, sz[i] = 1;
mset(isknown), mset(val);
bad = false;
mset(dep);
for(int i = 0; i < 100005; i++) e[i].clear();
return;
}
inline void dfs(int u, int fa){
for(auto p : e[u]){
int v = p.first, w = p.second;
if(v == fa) continue;
if(isknown[u] && isknown[v] && val[u] + val[v] != w) return bad = true, void();
val[v] = w - val[u], dep[v] = !dep[u];
if(isknown[u]) isknown[v] = true;
dfs(v, u);
}
return;
}
inline void Solve(){
clear();
while(q--){
int t = read(), x = read(), y = read(), v = read();
t = (t + M * L) % 2;
x = (x - 1 + M * L) % n + 1;
y = (y - 1 + M * L) % n + 1;
v = (v + M * L) % (W + 1);
if(t == 0){
if(isknown[x] && isknown[y] && val[x] + val[y] != v) bad = true;
if(bad || (isknown[x] && isknown[y])) continue;
if(find(x) == find(y)){
if(dep[x] != dep[y]){
if(val[x] + val[y] != v){
bad = true;
}
}else{
if((v + val[x] - val[y]) % 2 == 0 && (v - val[x] + val[y]) % 2 == 0){
isknown[x] = isknown[y] = true;
int temp1 = (v + val[x] - val[y]) >> 1, temp2 = (v - val[x] + val[y]) >> 1;
val[x] = temp1, val[y] = temp2;
dfs(x, 0);
}else bad = true;
}
}else{
if(sz[find(x)] < sz[find(y)]) swap(x, y);
int fx = find(x), fy = find(y);
if(isknown[x]){
isknown[y] = true, val[y] = v - val[x], dep[y] = !dep[x], dfs(y, 0);
fa[fy] = fx, sz[fx] += sz[fy];
}else if(isknown[y]){
isknown[x] = true, val[x] = v - val[y], dep[x] = !dep[y], dfs(x, 0);
fa[fx] = fy, sz[fy] += sz[fx];
}else{
val[y] = v - val[x], dep[y] = !dep[x], dfs(y, 0);
fa[fy] = fx, sz[fx] += sz[fy];
}
e[x].push_back({y, v}), e[y].push_back({x, v});
}
}else{
int fx = find(x), fy = find(y);
if(bad || (isknown[x] && val[x] != v)){
L = Impossible;
puts("Impossible");
}else if(fx != fy){
if(isknown[y]){
L = val[y] + Normal;
write(val[y]), putchar('\n');
}else{
L = Ambiguous;
puts("Ambiguous");
}
}else{
int ans = val[y] + (dep[x] != dep[y] ? -1 : 1) * (v - val[x]);
if(isknown[y] && val[y] != ans){
L = Impossible;
puts("Impossible");
}else{
L = ans + Normal;
write(ans), putchar('\n');
}
}
}
}
return;
}
signed main(){
freopen("equation.in", "r", stdin);
freopen("equation.out", "w", stdout);
T = read(), M = read(), W = read();
while(T--) Solve();
return 0;
}

浙公网安备 33010602011771号