QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#770663#6623. Perfect Matchingslonelywolf#WA 0ms3880kbC++209.4kb2024-11-21 23:05:522024-11-21 23:05:53

Judging History

This is the latest submission verdict.

  • [2024-11-21 23:05:53]
  • Judged
  • Verdict: WA
  • Time: 0ms
  • Memory: 3880kb
  • [2024-11-21 23:05:52]
  • Submitted

answer

#include <bits/stdc++.h>  
using namespace std;  

#define int long long  


constexpr int mod = 998244353;

int qpow(int x, int y) {
	int res = 1;
	for (; y; y /= 2, x = x * x % mod) {
		if (y % 2 == 1) {
			res = res * x % mod;
		}
	}
	return res;
}

vector<int> rev, roots{0, 1};
void dft(vector<int> &a) {
	int n = a.size();
	if ((int)rev.size() != n) {
		int k = __builtin_ctz(n) - 1;
		rev.resize(n);
		for (int i = 0; i < n; i++) {
			rev[i] = rev[i >> 1] >> 1 | (i & 1) << k;
		}
	}
	if ((int)roots.size() < n) {
		int k = __builtin_ctz(roots.size());
		roots.resize(n);
		while ((1LL << k) < n) {
			int e = qpow(3, (mod - 1) >> (k + 1));
			for (int i = 1LL << (k - 1); i < (1LL << k); i++) {
				roots[2 * i] = roots[i];
				roots[2 * i + 1] = roots[i] * e % mod;
			}
			k++;
		}
	}
	for (int i = 0; i < n; i++) {
		if (rev[i] < i) {
			swap(a[i], a[rev[i]]);
		}
	}
	for (int k = 1; k < n; k *= 2) {
		for (int i = 0; i < n; i += 2 * k) {
			for (int j = 0; j < k; j++) {
				int u = a[i + j];
				int v = a[i + j + k] * roots[j + k] % mod;
				a[i + j] = (u + v) % mod;
				a[i + j + k] = (u - v + mod) % mod;
			}
		}
	}
}
void idft(vector<int> &a) {
	int n = a.size();
	reverse(a.begin() + 1, a.end());
	dft(a);
	int inv = qpow(n, mod - 2);
	for (auto &x : a) {
		x = x * inv % mod;
	}
}

struct Poly {
	vector<int> a;

	Poly() {}
	Poly(const vector<int> &_a) 
		: a(_a) {}

	int size() const {
		return a.size();
	} 
	int operator[](int idx) const {
		if (idx < a.size()) {
			return a[idx];
		} else {
			return 0;
		}
	}
	// added by HTensor.
	Poly rev(int n) {
		vector<int> b(a);
		b.resize(n, 0);
		ranges::reverse(b);
		return Poly(b);
	}

	int &operator[](int idx) {
		return a[idx];
	}
	Poly mulXn(int n) const {
		auto b = a;
		b.insert(b.begin(), n, 0);
		return Poly(b);
	}
	Poly modXn(int n) const {
		if (n > size()) return *this;
		return Poly(vector<int>(a.begin(), a.begin() + n));
	}
	Poly divXn(int n) const {
		if (size() <= n) {
			return Poly();
		}
		return Poly(vector<int>(a.begin() + n, a.end()));
	}
	friend Poly operator+(const Poly &a, const Poly &b) {
		vector<int> res(max(a.size(), b.size()));
		for (int i = 0; i < res.size(); i++) {
			res[i] = a[i] + b[i];
			if (res[i] >= mod) {
				res[i] -= mod;
			}
		}
		return Poly(res);
	}
	friend Poly operator-(const Poly &a, const Poly &b) {
		vector<int> res(max(a.size(), b.size()));
		for (int i = 0; i < res.size(); i++) {
			res[i] = a[i] - b[i];
			if (res[i] < 0) {
				res[i] += mod;
			}
		}
		return Poly(res);
	}
	friend Poly operator*(Poly a, Poly b) {
		if (a.size() == 0 || b.size() == 0) {
            return Poly();
        }
        if (a.size() < b.size()) {
            swap(a, b);
        }
        if (b.size() < 128) {
            vector<int> c(a.size() + b.size() - 1);
            for (int i = 0; i < a.size(); i++) {
                for (int j = 0; j < b.size(); j++) {
                    c[i + j] += a[i] * b[j] % mod;
                    if (c[i + j] >= mod) {
                    	c[i + j] -= mod;
                    }
                }
            }
            return Poly(c);
        }
        int tot = a.size() + b.size() - 1;
       	int sz = 1LL << __lg(tot * 2 - 1); 
        a.a.resize(sz);
        b.a.resize(sz);
        dft(a.a);
        dft(b.a);
        for (int i = 0; i < sz; ++i) {
            a.a[i] = a[i] * b[i] % mod;
        }
        idft(a.a);
        a.a.resize(tot);
        return a;
	}
	friend Poly operator*(Poly a, int b) {
		for (int i = 0; i < a.size(); i++) {
			a[i] = a[i] * b % mod;
		}
		return a;
	}
	friend Poly operator*(int a, Poly b) {
		for (int i = 0; i < b.size(); i++) {
			b[i] = b[i] * a % mod;
		}
		return b;
	}
	friend Poly operator-(const Poly &a) {
		vector<int> res(a.size());
		for (int i = 0; i < a.size(); i++) {
			res[i] = a[i] == 0 ? a[i] : mod - a[i];
		}
		return Poly(res);
	}
	// added by HTensor.
	// F(x) = Q(x) * G(x) + R(x)
	// B(x) 最高次项不为 0
	// Q_R(x) = F_R(x) * G_R^{-1}(x) (\mod x^{n - m + 1})
	friend Poly operator/(Poly F, Poly G) {
		int n = F.size(), m = G.size();
		auto GR = G.rev(m).modXn(n - m + 1);
		auto GRinv = GR.inv(n - m + 1);
		auto AR = F.rev(n).modXn(n - m + 1);
		auto res = (AR * GRinv).modXn(n - m + 1);
		return res.rev(n - m + 1);
	}
	// added by HTensor.
	friend Poly operator%(Poly F, Poly G) {
		int m = G.size();
		return (F - G * (F / G)).modXn(m - 1);
	}
	// added by HTensor.
	friend ostream &operator<<(ostream& out, const Poly& b) {
		for(int i = 0; i < (int) b.size(); i++) {
			out << b[i] << " ";
		}
		return out;
	}
	Poly &operator+=(const Poly &a) {
		return (*this) = (*this) + a;
	}
	Poly &operator-=(const Poly &a) {
		return (*this) = (*this) - a;
	}
	Poly &operator*=(Poly a) {
		return (*this) = (*this) * a;
	}
	// 导数
	Poly derivation() const {
		if (a.empty()) {
			return Poly();
		}
		vector<int> res(size() - 1);
		for (int i = 0; i < size() - 1; i++) {
			res[i] = (i + 1) * a[i + 1] % mod;
		}
		return Poly(res);
	}
	Poly integral() const {
		if (a.empty()) {
			return Poly();
		}
		vector<int> res(size() + 1), inv(size() + 1, 1);
		for (int i = 2; i <= size(); i++) {
			inv[i] = (mod - mod / i) * inv[mod % i] % mod;
		}
		for (int i = 0; i < size(); i++) {
			res[i + 1] = a[i] * inv[i + 1] % mod;
		}
		return Poly(res);
	}
	Poly inv(int n) const {
		assert(a[0] != 0);
		Poly x({qpow(a[0], mod - 2)});
		int k = 1;
		while (k < n) {
			k *= 2;
			x = (x * (Poly({2}) - modXn(k) * x)).modXn(k);
		}
		return x.modXn(n);
	}
	Poly log(int n) const {
		assert(a[0] == 1);
		return (derivation() * inv(n)).integral().modXn(n);
	}
	Poly exp(int n) const {
		Poly x({1});
		int k = 1;
		while (k < n) {
			k *= 2;
			x = (x * (Poly({1}) - x.log(k) + modXn(k))).modXn(k);
		}
		return x.modXn(n);
	}
	Poly sqrt(int n) const {
		Poly x({1});
		int k = 1;
		while (k < n) {
			k *= 2;
			x += modXn(k) * x.inv(k);
			x = x.modXn(k) * ((mod + 1) / 2);
		}
		return x.modXn(n);
	}
	Poly pow(int k, int n) const {
		if (k == 0) {
			vector<int> ret(n);
			ret[0] = 1;
			return Poly(ret);
		}
        int i = 0;
        while (i < size() && a[i] == 0) {
            i++;
        }
        if (i == size() || i * k >= n) {
            return Poly(vector<int>(n));
        }
        int v = a[i];
        Poly f = divXn(i) * qpow(v, mod - 2);
        return (f.log(n - i * k) * k).exp(n - i * k).mulXn(i * k) * qpow(v, k);
    }
    // 减法卷积
    Poly mulT(Poly b) const {
        if (b.size() == 0) {
            return Poly();
        }
        int n = b.size();
        reverse(b.a.begin(), b.a.end());
        return ((*this) * b).divXn(n - 1);
    }
    int eval(int x) {
		int r = 0, t = 1;
		for (int i = 0; i < size(); i++) {
			r = (r + a[i] * t) % mod;
			t = t * x % mod;
		}
		return r;
	}
	vector<int> eval(vector<int> x) const {
        if (size() == 0) {
            return vector<int>(x.size(), 0);
        }
        const int n = max((int)x.size(), size());
        vector<Poly> q(4 * n);
        vector<int> ans(x.size());
        x.resize(n);
        function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                q[p] = Poly({1, -x[l]});
            } else {
                int m = (l + r) / 2;
                build(2 * p, l, m);
                build(2 * p + 1, m, r);
                q[p] = q[2 * p] * q[2 * p + 1];
            }
        };
        build(1, 0, n);
        function<void(int, int, int, const Poly &)> work = [&](int p, int l, int r, const Poly &num) {
            if (r - l == 1) {
                if (l < (int)ans.size()) {
                    ans[l] = num[0];
                }
            } else {
            	int m = (l + r) / 2;
                work(2 * p, l, m, num.mulT(q[2 * p + 1]).modXn(m - l));
                work(2 * p + 1, m, r, num.mulT(q[2 * p]).modXn(r - m));
            }
        };
        work(1, 0, n, mulT(q[1].inv(n)));
        return ans;
    }
};

signed main() {  
    ios::sync_with_stdio(false);
    cin.tie(nullptr);  

	int n;
	cin >> n;

	vector<vector<int>> adj(2 * n + 1);
	for (int i = 1; i < 2 * n; i++) {
		int x, y;
		cin >> x >> y;
		adj[x].push_back(y);
		adj[y].push_back(x);
	}

	vector<Poly> f(2 * n + 1), g(2 * n + 1), s(2 * n + 1);
	
	function<void(int, int)> dfs = [&](int x, int fa) {
		f[x] = Poly({1});
		g[x] = Poly({0});
		for (auto y : adj[x]) {
			if (y == fa) {
				continue;
			}
			dfs(y, x);
		}
		for (auto y : adj[x]) {
			if (y == fa) {
				continue;
			}
			f[x] = (f[x] * s[y]).modXn(n + 1);
		}
		for (auto y : adj[x]) {
			if (y == fa) {
				continue;
			}
			g[x] = (g[x] + f[x] / s[y] * f[y]).modXn(n + 1);
		}
		if (g[x].a != vector<int>(1, 0)) {
			g[x] = g[x].mulXn(1).modXn(n + 1);
		}
		s[x] = f[x] + g[x];
		// cout << s[x] << "\n";
	};

	dfs(1, 0);
	
	vector<int> t(2 * n + 1);
	t[0] = 1;
	t[2] = 1;
	for (int i = 4; i <= 2 * n; i += 2) {
		t[i] = t[i - 2] * (i - 1) % mod;
	}

	int ans = t[2 * n];
	// cout << ans << "\n";
	for (int i = 1; i <= n; i++) {
		// cout << s[1][i] << "\n";
		if (i % 2) {
			ans = (ans + mod - s[1][i] * t[2 * (n - i)] % mod) % mod;
		} else {
			ans = (ans + s[1][i] * t[2 * (n - i)] % mod) % mod;
		}
	}

	cout << ans << "\n";

    return 0;
}  
  

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 3648kb

input:

2
1 2
1 3
3 4

output:

1

result:

ok 1 number(s): "1"

Test #2:

score: 0
Accepted
time: 0ms
memory: 3584kb

input:

3
1 2
2 3
3 4
4 5
5 6

output:

5

result:

ok 1 number(s): "5"

Test #3:

score: -100
Wrong Answer
time: 0ms
memory: 3880kb

input:

10
2 1
3 2
4 2
5 3
6 3
7 5
8 4
9 3
10 5
11 3
12 9
13 11
14 8
15 5
16 1
17 4
18 1
19 11
20 19

output:

223263297

result:

wrong answer 1st numbers differ - expected: '223263378', found: '223263297'