闲话 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\) 成立),并直接枚举最后一段长度得到

\[f(n) = (m - 1) \sum_{i = 1}^{k - 1} f(n - i) \]

答案即为 \(\frac{m}{m - 1} f(n)\)

我们可以构造出 \(f\) 的生成函数 \(F(x)\),因为其满足

\[F = (m - 1) \sum_{i = 1}^{k - 1} x^i F + 1 \]

\[F(x) = \frac{1 - x}{1 - mx + (m - 1)x^k} \]

不考虑乘 \(1 - x\),我们也可以提取它的第 \(n\) 项系数:

\[\begin{aligned} & [x^n]\left(1 - mx + (m - 1)x^k\right)^{-1} \\ = \ & [x^n]\sum_{i \ge 0} (-1)^i \left(- mx + (m - 1)x^k\right)^{i} \\ = \ & [x^n]\sum_{i \ge 0} \left( mx + (1 - m)x^k\right)^{i} \\ = \ & [x^n]\sum_{i \ge 0} \sum_{j \ge 0} \binom{i}{j} m^{i - j} (1 - m)^{j} x^{jk + i - j} \\ = \ & [x^n]\sum_{i \ge 0} \sum_{j \ge 0} \binom{i}{j} m^{i - j} (1 - m)^{j} x^{jk + i - j} \\ = \ & \sum_{j \ge 0} \binom{n - j(k - 1)}{j} m^{n - jk} (1 - m)^{j} \end{aligned}\]

可以发现直接 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 皇后问题的解是相对多的,我们只要能进入一个搜索树的子树即可。

存在 \(O(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;
}
posted @ 2023-02-14 19:08  joke3579  阅读(85)  评论(3编辑  收藏  举报