// 首先按顺序分配给所有存在的“早段” for (int i = 1; i <= n; i++) { if (x[i] > 0) { early_val[i] = current_val++; } } // 然后按顺序分配给所有存在的“晚段” for (int i = 1; i <= n; i++) { longlong y = k - x[i]; if (y > 0) { late_val[i] = current_val++; } }
// 按要求输出 n*k 个序列数字 bool first = true; for (int i = 1; i <= n; i++) { // 输出早段的数字 for (int j = 0; j < x[i]; j++) { if (!first) cout << " "; cout << early_val[i]; first = false; } // 输出晚段的数字 longlong y = k - x[i]; for (int j = 0; j < y; j++) { if (!first) cout << " "; cout << late_val[i]; first = false; } } cout << "\n"; }
\begin{minted}{cpp} #include <iostream> #include <vector> #include <algorithm> using namespace std; void solve() { long long n, m, k; if (!(cin >> n >> m >> k)) return; // w 为获胜所需的最少场数 long long w = (1LL * k * k) / 2 + 1; // R 为推导出的常数界限 long long R = 1LL * k * k - w; vector<long long> x(n + 1); // 贪心确定 1 号骰子的最大早段容量 x[1] = k - (w + k - 1) / k; // 递推贪心确定后续骰子的最大早段容量 for (int i = 2; i <= n; i++) { long long denom = k - x[i - 1]; if (denom == 0) { x[i] = k; } else { x[i] = min((long long)k, R / denom); } } // current_val 用于按顺序分配递增的数值 long long current_val = 0; vector<long long> early_val(n + 1, -1); vector<long long> late_val(n + 1, -1); // 阶段一:按顺序给所有骰子的“早段”分配小数值 for (int i = 1; i <= n; i++) { if (x[i] > 0) { early_val[i] = current_val++; } } // 阶段二:按顺序给所有骰子的“晚段”分配大数值 for (int i = 1; i <= n; i++) { long long y = k - x[i]; if (y > 0) { late_val[i] = current_val++; } } // 按照 1 到 n 号骰子的顺序,格式化输出所有的面 bool first = true; for (int i = 1; i <= n; i++) { // 输出早段 for (int j = 0; j < x[i]; j++) { if (!first) cout << " "; cout << early_val[i]; first = false; } // 输出晚段 long long y = k - x[i]; for (int j = 0; j < y; j++) { if (!first) cout << " "; cout << late_val[i]; first = false; } } cout << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int t; if (cin >> t) { while (t--) solve(); } return 0; } \end{minted}
// 模 p 意义下的线性基(用于处理 p 进制下的无进位加法,本题中 p = 3) classmodn_XOR_base { private: vector<ll> base; // 记录主元位置对应的原始数值 vector<vector<ll>> mat; // mat[i] 存储最高位为 i 且系数已被标准化为 1 的基向量 ll mod; // 模数 p(要求 p 为质数,才能使用费马小定理求逆元)
// 快速幂计算 (a^b % mod) ll power(ll a, ll b)const{ ll res = 1; a %= mod; while (b > 0) { if (b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1; } return res; }
// 费马小定理求逆元(因为 mod 为质数) ll modInverse(ll n)const{ returnpower(n, mod - 2); }
// 插入元素 x 到线性基中 // 如果 x 能被已有的线性基表出,返回 false;否则将其作为新的基插入并返回 true boolinsert(ll x){ ll orig_x = x; vector<ll> v(64, 0); // 将 x 转换为 mod 进制的向量表示(从低位到高位分离) for (int i = 0; i < 64; ++i) { v[i] = x % mod; x /= mod; }
// 从高位到低位进行高斯消元操作 for (int i = 63; i >= 0; --i) { if (v[i] == 0) continue; // 当前位为 0,无需处理
// 查询元素 x 能否被当前的线性基表出 boolquery(ll x)const{ vector<ll> v(64, 0); // 同样将待查询的 x 转换为 mod 进制的向量表示 for (int i = 0; i < 64; ++i) { v[i] = x % mod; x /= mod; }
// 从高位到低位依次尝试被线性基消元 for (int i = 63; i >= 0; --i) { if (v[i] == 0) continue; // 如果 x 在某一位不为 0,但线性基该位为空,说明无法被表出,直接返回 false if (base[i] == 0) returnfalse;
// 利用线性基消去当前位 ll k = v[i]; for (int j = 0; j <= i; ++j) { v[j] = (v[j] - k * mat[i][j]) % mod; if (v[j] < 0) v[j] += mod; } } // 如果所有非零位都被成功消去(最终变为全 0 向量),说明 x 能被完美表出 returntrue; } };