闲话 23.2.14
闲话
soytony 老师和 apj 老师来了
看着他俩打情骂俏真的很有意思(
今天放的歌是《阳光彩虹小白马》
guge 说:这歌就蛮好听的 提神醒脑(?)
感觉只要隔了十年 对歌的品味就会有差别
少年时的感受是长大了不会再有的吧
今日推歌:美影日记
好又一次在我脑子里循环播放了
题解
惯例题解。其实主要是有些好玩(?)题,写写
T1 光明 (light)
场上想了个二分 + dsuontree + 树状数组的 \(O(n\log^3n)\) 做法
场下发现树状数组根本不需要 彳亍
我们发现我们可以快速求得 \(\ge\) 一个值的 \(f\) 的出现次数和求和,因此不妨考虑二分答案转化为判定。
出现次数可以考虑做 dsuontree。我们发现 \(f(u, i)\) 本质上就是 \(f(i + dep(u))\),即到根距离为 \(i\) 的数。这是经典问题了,直接做 dsuontree 即可在 \(O(n\log n)\) 的复杂度内求得 \(\ge \text{mid}\) 的 \(f(i + dep(u))\) 数量和求和。不需要树状数组,只需要在 \(f(i)\) 越过 \(\text{mid}\) 的分界线时处理即可。
因此可以做到 \(O(n\log^2 n)\)。
接下来就是卡常了。使用链式前向星存边,并将 dsuontree 的操作顺序离线即可通过。可以做到比 O(n) 正解快。
apj 老师说可以一次 dsu 得到桶 然后就是 \(O(n\log n)\)
题解给出的做法是应用长链剖分维护 \(f\) 的信息,可以做到 \(O(n)\) 求解。
code: 长链剖分
#include <bits/stdc++.h>
using namespace std;
#define int long long
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long;
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(file) freopen(#file".in", "r", stdin), freopen(#file".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 3e6 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
using namespace std;
int n, f, t, head[N];
long long k, ans;
struct ep {
int v, next;
} e[N];
void add(int u, int v) {
e[++t].v = v;
e[t].next = head[u];
head[u] = t;
}
int dis[N], son[N], len[N], dep[N];
void dfs1(int u, int f) {
dep[u] = dep[f] + 1;
for (int i = head[u]; i; i = e[i].next) {
dfs1(e[i].v, u);
if (dis[son[u]] < dis[e[i].v]) son[u] = e[i].v;
} dis[u] = dis[son[u]] + 1;
}
void dfs2(int u, int tp) {
len[u] = dep[u] - dep[tp] + 1;
if (son[u]) dfs2(son[u], tp);
for (int i = head[u]; i; i = e[i].next)
if (e[i].v != son[u]) dfs2(e[i].v, e[i].v);
}
int s[N], buf[N];
int *dp[N], *now = buf;
void dfs(int u) {
if (son[u]) dp[son[u]] = dp[u] + 1, dfs(son[u]);
int mx = 0;
for (int i = head[u]; i; i = e[i].next) if (e[i].v != son[u])
mx = max(mx, dis[e[i].v]);
rep(i,1,mx) s[dp[u][i]] -= len[u];
dp[u][0] = 1;
for (int i = head[u]; i; i = e[i].next) if (e[i].v != son[u]) {
dp[e[i].v] = now;
now += dis[e[i].v];
dfs(e[i].v);
for (int j = 1; j <= dis[e[i].v]; j++) dp[u][j] += dp[e[i].v][j - 1];
} rep(i,0,mx) s[dp[u][i]] += len[u];
}
signed main() {
cin >> n >> k;
rep(i,2,n) cin >> f, add(f, i);
dfs1(1, 0), dfs2(1, 1);
dp[1] = now; now += dis[1];
dfs(1);
pre(i,n,1) {
long long ret = min(k, 1ll * s[i]);
ans += 1ll * ret * i, k -= ret;
} cout << ans << '\n';
}
code: dsuontree
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long;
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 3e6 + 10;
int n, fa[N], dep[N], mxdp;
ll k;
namespace sol {
#define Aster(u) for (int i = head[u], v; i; i = e[i].nxt)
int head[N], mlc;
struct ep {
int to, nxt;
} e[N];
void adde(int u, int v) {
e[++ mlc] = {v, head[u]}; head[u] = mlc;
}
int siz[N], son[N];
void dfs1(int u) {
siz[u] = 1;
Aster(u) {
dfs1(v = e[i].to); siz[u] += siz[v];
if (siz[v] >= siz[son[u]])
son[u] = v;
}
}
namespace dsucnt {
ll ret, now;
int f[N], bnd;
int cnt, opr[70000000];
void addans(int u) {
opr[++ cnt] = dep[u];
Aster(u) addans(e[i].to);
}
void clear(int u) {
opr[++ cnt] = - dep[u];
Aster(u) clear(e[i].to);
}
void dsu(int u, bool need_clear) {
Aster(u) if ((v = e[i].to) != son[u])
dsu(v, 1);
if (son[u]) dsu(son[u], 0);
Aster(u) if ((v = e[i].to) != son[u])
addans(v);
opr[++ cnt] = dep[u];
opr[++ cnt] = 0;
if (need_clear) clear(u);
}
void init() { dsu(1, 1); }
ll calc(int val) {
ret = 0, bnd = val, now = 0;
if (bnd == 0) now = n;
rep(i,1,cnt) {
if (opr[i] == 0) ret += now;
else {
if (opr[i] < 0) {
f[- opr[i]] --;
(f[- opr[i]] == bnd - 1) && (-- now, true);
} else {
f[opr[i]] ++;
(f[opr[i]] == bnd) && ++ now;
}
}
} return ret;
}
}
namespace dsuval {
ll ret, bnd, now;
int f[N];
void addans(int u) {
int &x = f[dep[u]];
(x >= bnd) && (now -= x);
x ++;
(x >= bnd) && (now += x);
Aster(u) addans(e[i].to);
}
void clear(int u) {
int &x = f[dep[u]];
(x >= bnd) && (now -= x);
x --;
(x >= bnd) && (now += x);
Aster(u) clear(e[i].to);
}
void dsu(int u, bool need_clear) {
Aster(u) (e[i].to != son[u]) && (dsu(e[i].to, 1), 1);
if (son[u]) dsu(son[u], 0);
Aster(u) (e[i].to != son[u]) && (addans(e[i].to), 1);
int &x = f[dep[u]];
(x >= bnd) && (now -= x);
x ++;
(x >= bnd) && (now += x);
ret += now;
if (need_clear) clear(u);
}
ll calc(int val) {
ret = 0; bnd = val;
dsu(1, 0);
return ret;
}
}
void main() {
rep(i,2,n) adde(fa[i], i);
dfs1(1);
int l = 1, r = mxdp, mid, kth = 0;
dsucnt :: init(); cerr << dsucnt :: cnt << '\n';
while (l <= r) {
mid = l + r >> 1;
if (dsucnt :: calc(mid) >= k) kth = mid, l = mid + 1;
else r = mid - 1;
}
cout << dsuval :: calc(kth + 1) + 1ll * (k - dsucnt :: calc(kth + 1)) * kth << '\n';
}
}
signed main() {
cin >> n >> k;
dep[1] = 1;
rep(i,2,n) cin >> fa[i], dep[i] = dep[fa[i]] + 1;
mxdp = *max_element(dep + 1, dep + 1 + n);
sol :: main();
}
T2 游戏 (game)
容易看出我们需要计数的就是 \(n\) 长度序列染 \(m\) 种颜色的方案,使得至少存在一条长度 \(\ge 2k - 1\) 的颜色连续段。下面记 \(k = 2k - 1\)。
我们考虑计算不存在这样的连续段的染色方案,然后用 \(m^n\) 减去即可。
这可以 dp 求解。具体的,设 \(f(n)\) 为考虑前 \(n\) 个位置的染色情况(\(f(n) = 0\) 对所有 \(n \le 0\) 成立),并直接枚举最后一段长度得到
答案即为 \(\frac{m}{m - 1} f(n)\)。
我们可以构造出 \(f\) 的生成函数 \(F(x)\),因为其满足
即
不考虑乘 \(1 - x\),我们也可以提取它的第 \(n\) 项系数:
可以发现直接 lucas 方法求的复杂度是 \(O(n / k \log_p(n))\) 的。这样在 \(k\) 很小的时候复杂度会炸。怎么办呢?
考虑阈值分治。
我们发现,当 \(k\) 小的时候我们可以直接应用 Bostan-Mori 算法,做到 \(O(k\log k\log n)\),而当 \(k\) 大的时候直接处理组合数即可 \(O(n / k \log_p(n))\)。
这样当 \(k \log k \ge \sqrt n\) 时处理组合数,反之作线性递推即可。
code
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long;
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(file) freopen(#file".in", "r", stdin), freopen(#file".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 3e6 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
ll n, k, m;
int mod = 998244353;
int qp(int a, int b, int p = mod) {
int ret = 1;
while (b) {
if (b & 1) ret = 1ll * ret * a % p;
a = 1ll * a * a % p;
b >>= 1;
} return ret;
}
using db = double;
struct cp {
db x, y;
cp(db real = 0, db imag = 0) : x(real), y(imag){};
cp operator+(cp b) const { return {x + b.x, y + b.y}; }
cp operator-(cp b) const { return {x - b.x, y - b.y}; }
cp operator*(cp b) const { return {x * b.x - y * b.y, x * b.y + y * b.x}; }
};
using vcp = vector<cp>;
namespace FFT {
const db pi = acos(-1);
vcp Omega(int L) {
vcp w(L); w[1] = 1;
for (register int i = 2; i < L; i <<= 1) {
auto w0 = w.begin() + i / 2, w1 = w.begin() + i;
cp wn(cos(pi / i), sin(pi / i));
for (register int j = 0; j < i; j += 2)
w1[j] = w0[j >> 1], w1[j + 1] = w1[j] * wn;
} return w;
} auto W = Omega(1 << 21);
void DIF(cp *a, int n) {
cp x, y;
for (register int k = n >> 1; k; k >>= 1)
for (register int i = 0; i < n; i += k << 1)
for (register int j = 0; j < k; ++j)
x = a[i + j], y = a[i + j + k],
a[i + j + k] = (x - y) * W[k + j], a[i + j] = x + y;
}
void IDIT(cp *a, int n) {
cp x, y;
for (register int k = 1; k < n; k <<= 1)
for (register int i = 0; i < n; i += k << 1)
for (register int j = 0; j < k; ++j)
x = a[i + j], y = a[i + j + k] * W[k + j],
a[i + j + k] = x - y, a[i + j] = x + y;
const db Inv = 1. / n;
rep(i, 0, n - 1) a[i].x *= Inv, a[i].y *= Inv;
reverse(a + 1, a + n);
}
}
namespace Polynomial {
using poly = vector<int>;
void DFT(vcp &a) { FFT::DIF(a.data(), a.size()); }
void IDFT(vcp &a) { FFT::IDIT(a.data(), a.size()); }
int norm(int n) { return 1 << (__lg(n - 1) + 1); }
poly operator*(poly &a, poly &b) {
int n = a.size() + b.size() - 1;
vcp c(norm(n));
rep(i, 0, a.size() - 1) c[i].x = a[i];
rep(i, 0, b.size() - 1) c[i].y = b[i];
DFT(c);
rep(i, 0, a.size() - 1) c[i] = c[i] * c[i];
IDFT(c), a.resize(n);
rep(i, 0, n - 1) a[i] = int(c[i].y * .5 + .5);
return a;
}
poly conv(const poly &a, const poly &b, const int&P = mod) {
int n = a.size(), m = b.size(), o = n + m - 1, l = norm(o);
vcp A(l), B(l), c0(l), c1(l);
for (register int i = 0; i < n; i++) A[i] = cp(a[i] & 0x7fff, a[i] >> 15);
for (register int i = 0; i < m; i++) B[i] = cp(b[i] & 0x7fff, b[i] >> 15);
FFT::DIF(A.data(), l), FFT::DIF(B.data(), l);
for (register int k = 1, i = 0, j; k < l; k <<= 1)
for ( ; i < k * 2; i++) {
j = i ^ k - 1;
c0[i] = cp(A[i].x + A[j].x, A[i].y - A[j].y) * B[i] * 0.5;
c1[i] = cp(A[i].y + A[j].y, -A[i].x + A[j].x) * B[i] * 0.5;
}
FFT::IDIT(c0.data(), l), FFT::IDIT(c1.data(), l);
poly res(o);
for (register int i = 0; i < o; i++) {
ll c00 = c0[i].x + 0.5, c01 = c0[i].y + 0.5, c10 = c1[i].x + 0.5, c11 = c1[i].y + 0.5;
res[i] = (c00 + ((c01 + c10) % P << 15) + (c11 % P << 30)) % P;
}
return res;
}
poly Inv(const poly& f, const int &p = mod) {
int o = f.size(), _n = norm(o); poly g(1), h;
g[0] = qp(f[0], p - 2, p);
for (int len = 2; len <= _n; len <<= 1) {
h.assign(f.begin(), f.begin() + min(len, (int)f.size()));
h = conv( g, conv( g, h, p ), p );
g.resize(len);
for (int i = 0; i < len; ++ i)
g[i] = (2ll * g[i] - h[i] + p) % p;
} g.resize(o);
return g;
}
poly Deri(const poly& f, const int& p = mod) {
poly ret; ret.resize(f.size());
for (int i = 0; i + 1 < f.size(); ++i) {
ret[i] = 1ll * f[i+1] * (i+1) % p;
} return ret;
} poly Intg(const poly& f, const int& p = mod) {
poly ret; ret.resize(f.size());
static int __Inv[N]; __Inv[0] = __Inv[1] = 1;
for (int i = 2; i < f.size(); ++ i)
__Inv[i] = 1ll * (p - p / i) * __Inv[p % i] % p;
for (int i = f.size() - 1; i >= 1; --i) {
ret[i] = 1ll * f[i-1] * __Inv[i] % p;
} return ret;
}
poly Ln(const poly& f, const int& p = mod) {
poly ret = Deri(f, p), Iv = Inv(f, p);
ret = conv(ret, Iv, p); ret = Intg(ret, p);
ret.resize(f.size());
return ret;
}
poly Exp(const poly& f, const int& p = mod) {
poly ret; ret.resize(1); ret[0] = 1;
poly A, B;
for (register int len = 2; len < (f.size() << 1); len <<= 1) {
ret.resize(len); A = Ln(ret);
B.assign(f.begin(), f.begin() + min(len, (int)f.size()));
if (B.size() < A.size()) B.resize(A.size());
for (int i = 0; i < A.size(); ++ i){
B[i] -= A[i]; if (B[i] < 0) B[i] += p;
} B[0]++; ret = conv(ret, B);
ret.resize(len);
} ret.resize(f.size());
return ret;
}
} using namespace Polynomial;
/* add / sub */ template<typename T1,typename T2>T1 add(T1 a,T2 b){return(a+=b)>=mod?a-mod:a;}template<typename T1,typename...Args>T1 add(T1 a,Args...b){return add(a,add(b...));}template<typename T1,typename T2>T1 sub(T1 a,T2 b){return(a-=b)<0?a+mod:a;}template<typename T1,typename...Args>T1 sub(T1 a,Args...b){return sub(a,add(b...));}template<typename T1,typename T2>void addi(T1&a,T2 b){(a+=b)>=mod?(a-=mod):true;}template<typename T1,typename...Args>void addi(T1&a,Args...b){addi(a,add(b...));}template<typename T1,typename T2>void subi(T1&a,T2 b){(a-=b)<0?(a+=mod):true;}template<typename T1,typename...Args>void subi(T1&a,Args...b){subi(a,add(b...));}
/* Fastmod / mul */ struct FastMod{int m;ll b;void init(int _m){m=_m;if(m==0)m=1;b=((lll)1<<64)/m;}FastMod(int _m){init(_m);}int operator()(ll a){ll q=((lll)a*b)>>64;a-=q*m;if(a>=m)a-=m;return a;}}Mod(mod);int mul(int a,int b){return Mod(1ll*a*b);}template<typename T1,typename T2>int mul(T1 a,T2 b){return Mod((long long)(1ll*a*b));}template<typename T,typename...Args>int mul(T a,Args...b){return mul(a,mul(b...));}template<typename T1,typename T2>void muli(T1&a,T2 b){a=Mod(1ll*a*b);}template<typename T1,typename...Args>void muli(T1&a,Args...b){muli(a,mul(b...));} // /* trivial multiple function(idk whether its useful*/ int mul(int a, int b) { return 1ll * a * b % mod; } template <typename T1, typename T2> int mul(T1 a, T2 b) { return (long long)(1ll * a * b) % mod; } template <typename T, typename ...Args> int mul(T a, Args ...b) { return mul(a, mul(b...)); }
/* qp fac C */ template<typename T1,typename T2>T1 qp(T1 a,T2 b){T1 ret=1;for(;b>0;a=1ll*a*a%mod,b>>=1)if(b&1)ret=mul(ret,a);return ret;}vi __fac({1,1}),__ifc({1,1}),__inv({0,1});inline void ___prep(int n){static int i=2;if(i<n)for(__fac.resize(n),__ifc.resize(n),__inv.resize(n);i<n;i++)__fac[i]=mul(i,__fac[i-1]),__inv[i]=mul((mod-mod/i),__inv[mod%i]),__ifc[i]=mul(__inv[i],__ifc[i-1]);}inline int fac(int x){return ___prep(x+1),__fac[x];}inline int ifc(int x){return ___prep(x+1),__ifc[x];}inline int inv(int x){return ___prep(x+1),__inv[x];}
// /* sum of i^k */ int S(int n,int k){vector<int>__pre(k+4),__suf(k+4),__pw(k+4),__pri(k+4);vector<bool>__vis(k+4,0);__pw[1]=1;for(int i=2,cnt=0;i<=k+2;++i){if(!__vis[i])__pri[++cnt]=i,__pw[i]=qp(i,k);for(int j=1;j<=cnt and i*__pri[j]<=k+2;++j){__vis[i*__pri[j]]=1;__pw[i*__pri[j]]=mul(__pw[i],__pw[__pri[j]]);if(i%__pri[j]==0)break;}}rep(i,2,k+2)__pw[i]=add(__pw[i],__pw[i-1]);__pre[0]=__suf[k+3]=1;rep(i,1,k+2)__pre[i]=mul(__pre[i-1],(n-i+mod));pre(i,k+2,1)__suf[i]=mul(__suf[i+1],(n-i+mod));int tmp=0,ret=0;rep(i,1,k+2){if((k-i)&1)subi(ret,mul(__pw[i],__pre[i-1],__suf[i+1],ifc(i-1),ifc(k+2-i)));else addi(ret,mul(__pw[i],__pre[i-1],__suf[i+1],ifc(i-1),ifc(k+2-i)));}return ret;}
// /* inv 2/3/6 / phi */ constexpr int __var_pow(int a, int b) { int ret = 1; for (; b > 0; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod; return ret; } constexpr int __var_phi(int x) { if (x <= 2) return 1; int ret = x; for (int i = 2; 1ll * i * i <= x; ++i) if (x % i == 0) { ret = ret / i * (i - 1); while (x % i == 0) x /= i; } if (x > 1) ret = ret / x * (x - 1); return ret; } const int __phi_mod = __var_phi(mod); const int inv2 = __var_pow(2, __phi_mod - 1), inv3 = __var_pow(3, __phi_mod - 1), inv6 = __var_pow(6, __phi_mod - 1);
inline int C(int n, int k) {
int ret = 1;
while (n or k) {
int _n = n % mod, _k = k % mod;
if (_n < _k) return 0;
muli(ret, fac(_n), ifc(_k), ifc(_n - _k));
n /= mod, k /= mod;
} return ret;
}
int solve(int n) {
int ret = 0;
for (int i = 0; 1ll * i * k <= n; ++ i) {
addi(ret, mul(C(n - (k - 1) * i, i), qp(m, n - k * i), qp(sub(1, Mod(m)), i)));
}
return ret;
}
int main() {
iot; file(game);
cin >> n >> m >> k >> mod; Mod.init(mod);
if (k == 1) return cout << qp(m, n) << '\n', 0;
k = (k << 1) - 1;
int tot = qp(m, n);
poly P(k + 1), Q(k + 1), tmp(k + 2);
P[0] = 1, P[1] = mod - 1;
Q[0] = 1, Q[1] = sub(0, Mod(m)), Q[k] = sub(Mod(m), 1);
while (k * log2(k) > sqrt(n)) {
rep(i,0,k) tmp[i] = mul(i & 1 ? mod - 1 : 1, Q[i]);
P = conv(tmp, P), Q = conv(tmp, Q);
rep(i,0,k) Q[i] = Q[i << 1], P[i] = P[i << 1 | (n & 1)];
P.resize(k + 1), Q.resize(k + 1);
n >>= 1;
}
cout << sub(tot, mul(m, qp(m - 1, mod - 2), P[0], qp(Q[0], mod - 2))) << '\n';
}
T3 皇后 (queen)
我没用调整法,但是膜 dengls
我的做法是基于暴力的随机化优化。我们可以顺着扫每一行,对每行遍历所有可能求解的列即可。这样的复杂度是 O(跑不动大于 50 的点)。
然后考虑随机化。我们记录当前可以填的所有列,过程中用 vector 暴力维护即可。在每一行复制这个 vector 后 shuffle,按随机顺序递归求解。
在多次重复(跑一分钟没有出解就退出程序再跑一次)和足够的运气下,我们能在 10s 内不稳定地得到 \(\le 50000\) 的任意答案。
感性理解程序的表现,我们能发现 n 皇后问题的解是相对多的,我们只要能进入一个搜索树的子树即可。
code:打表程序
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>; using vi = vector<int>; using vp = vector<pii>; using ll = long long;
using ull = unsigned long long; using db = double; using ld = long double; using lll = __int128_t;
template<typename T1, typename T2> T1 max(T1 a, T2 b) { return a > b ? a : b; }
template<typename T1, typename T2> T1 min(T1 a, T2 b) { return a < b ? a : b; }
#define multi int T; cin >> T; while ( T -- )
#define timer cerr << 1. * clock() / CLOCKS_PER_SEC << '\n';
#define iot ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
#define eb emplace_back
#define pb pop_back
const int N = 3e5 + 10;
const int inf = 0x3f3f3f3f;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
int n, heng[N], shu[N], zuox[N << 1], youx[N << 1];
mt19937 rnd(random_device { } ());
vector<int> vec;
vp ans;
bool place(int x, int y) {
if (heng[x] or shu[y] or zuox[x + y] or youx[x - y + n + 1]) return false;
heng[x] ++, shu[y] ++;
zuox[x + y] ++, youx[x - y + n + 1] ++;
ans.eb(x, y);
vec.erase(lower_bound(vec.begin(), vec.end(), y));
return true;
}
void erase(int x, int y) {
heng[x] --, shu[y] --;
zuox[x + y] --, youx[x - y + n + 1] --;
vec.insert(lower_bound(vec.begin(), vec.end(), y), y);
ans.pop_back();
}
void dfs(int x) {
if (x == n + 1) {
for (auto [x, y] : ans) {
cout << x << ' ' << y << '\n';
}
timer;
exit(0);
}
vi g = vec;
shuffle(g.begin(), g.end(), rnd);
for (auto y : g) {
if (place(x, y)) {
dfs(x + 1);
erase(x, y);
}
}
}
signed main() {
cin >> n;
rep(i,1,n) vec.eb(i);
dfs(1);
puts("-1");
timer;
}
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat230214.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。