首页 > 其他分享 >abc269

abc269

时间:2022-09-20 21:58:42浏览次数:54  
标签:qolys int cdots vector solve dp abc269

\(\textbf{G.}\)

设 \(c _ i = b _ i - a _ i\), \(S _ a = \sum _ {i = 1} ^ {n} a _ i\). 则此时 \(k\) 的答案为选择最少个数的 \(c\) 凑出 \(k - S _ a\) 的答案.

注意到 \(\sum _ {i = 1} ^ {n} c _ i \leq \sum _ {i = 1} ^ {n} b _ i \leq m\). 所以 \(c _ 1, \cdots, c _ n\) 中本质不同的数的个数是 \(\mathcal{O}(\sqrt{m})\) 级别的. 将这些相同的 \(c\) 合并起来变成 \(\mathcal{O}(\sqrt{m})\) 种元素的多重背包. 之后只需二进制拆分重新变成 \(\mathcal{O}(\sqrt{m} \log n)\) 种元素的零一背包.

直接 dp 即可. 时间复杂度 \(\mathcal{O}(n + m \sqrt{m} \log n)\).

void solve(){
	int n, m;
	cin >> n >> m;
	vector<int> a(n + 1), b(n + 1);
	for(int i = 1; i <= n; i ++)
		cin >> a[i] >> b[i];

	int suma = accumulate(a.begin() + 1, a.begin() + n + 1, 0);
	map<int, int> cnt;
	for(int i = 1; i <= n; i ++)
		cnt[b[i] - a[i]] ++;
	vector<pair<int, int>> prod;
	for(auto it : cnt){
		int c = it.first, cntc = it.second;
		for(int dntc = 1; dntc <= cntc; dntc <<= 1){
			prod.emplace_back(dntc * c, dntc), cntc -= dntc;
		}
		prod.emplace_back(cntc * c, cntc);
	}

	vector<int> dp(m + 1, n + 1);
	dp[suma] = 0;
	for(auto [w, v] : prod){
		if(w > 0){
			for(int i = m; i >= w; i --)
				if(dp[i] > dp[i - w] + v)
					dp[i] = dp[i - w] + v;
		}
		if(w < 0){
			for(int i = 0; i <= m + w; i ++)
				if(dp[i] > dp[i - w] + v)
					dp[i] = dp[i - w] + v;
		}
	}
	for(int i = 0; i <= m; i ++)
		cout << (dp[i] == n + 1 ? -1 : dp[i]) << "\n";
}

\(\textbf{H.}\)

设 \(f(u, t)\) 表示在 \(u\) 子树内选择大小为 \(t\) 的反链的方案数.

则 \(f(u, t) = [t = 1] + \sum _ {t _ 1 + \cdots + t _ k = t} f(v _ 1, t _ 1) \cdots f(v _ k, t _ k)\), 其中 \(v _ 1, \cdots, v _ k\) 是 \(u\) 的所有儿子.

设 \(f(u) = \sum _ {t \geq 1} f(u, t) x ^ t\) 是以 \(t\) 为下标的生成函数. 那么 \(f(u) = x + \prod _ {v \in \mathcal{C} _ u} f(v)\).

考虑预处理出 \(u\) 的重儿子 \(h _ u\). 考虑设 \(g(u) = \prod _ {v \in \mathcal{C} _ u - \{ h _ u \}} f(v)\). 那么 \(f(u) = x + g(u) f(h _ u)\).

所以 \(\begin{array}{l} f(u) &= x + g(u) f(h _ u) = x + g(u) (x + g(h _ u) f(h _ {h _ u})) = x(1 + g(u)) + g(u) g(h _ u) f(h _ {h _ u}) \\ &= \cdots = x(1 + g(u) + g(u) g(h _ u) + \cdots) + (x + 1) g(u) g(h _ u) \cdots \end{array}\).

其中依次展开到 \(u\) 的重儿子直到叶子. 我们只在一条重链的顶端计算 \(f(u)\).

考虑快速计算 \(1 + p _ 1 + p _ 1 p _ 2 + \cdots + p _ 1 \cdots p _ k\) 和 \(p _ 1 \cdots p _ k\). 这东西可以通过分治 fft 在 \(\mathcal{O}((\deg p _ 1 + \cdots + \deg p _ k) \log ^ 2 n)\) 内计算.

而显然每个点 \(g(v)\) 显然只会使用恰好 \(1\) 次, 所以每次计算 \(g(v)\) 的时候通过用 huffman树 合并度数 ntt 计算即可. 复杂度为 \(\mathcal{O}((\deg p _ 1 + \cdots + \deg p _ k) \log ^ 2 n)\).

总时间复杂度 \(\mathcal{O}(n \log ^ 3 n)\). 常数很小.

void solve(){
	int n;
	cin >> n;
	vector<int> par(n + 1);
	vector<vector<int>> sons(n + 1);
	for(int i = 2; i <= n; i ++){
		cin >> par[i];
		sons[par[i]].emplace_back(i);
	}

	vector<int> siz(n + 1), h(n + 1);
	for(int i = n; i >= 1; i --){
		siz[i] = 1;
		for(int j : sons[i])
			siz[i] += siz[j];

		for(int j : sons[i])
			if(siz[j] > siz[h[i]])
				h[i] = j;
	}

	struct cmp{
		bool operator ()(const vector<modint> &F, const vector<modint> &G) const {
			return (int)F.size() > (int)G.size();
		}
	} ;
	auto solve = [&](auto solve, const vector<vector<modint>> &polys, int L, int R) -> pair<vector<modint>, vector<modint>> {
		if(L == R)
			return {polys[L], vector<modint>{modint(1)}};
		int M = (L + R) / 2;
		auto [PL, QL] = solve(solve, polys, L, M);
		auto [PR, QR] = solve(solve, polys, M + 1, R);
		return {mul(PL, PR), add(QL, mul(PL, QR))};
	} ;

	vector<vector<modint>> f(n + 1);
	for(int i = n; i >= 1; i --){
		if(h[par[i]] != i){
			vector<vector<modint>> polys;
			for(int j = i; j; j = h[j]){
				priority_queue<vector<modint>, vector<vector<modint>>, cmp> qolys;
				for(int k : sons[j])
					if(k != h[j])
						qolys.emplace(f[k]);
				if(qolys.empty())
					qolys.emplace(vector<modint>{modint(1)});
				while((int)qolys.size() >= 2){
					vector<modint> P = qolys.top(); qolys.pop();
					vector<modint> Q = qolys.top(); qolys.pop();
					qolys.emplace(mul(P, Q));
				}
				polys.emplace_back(qolys.top());
			}
			auto [P, Q] = solve(solve, polys, 0, (int)polys.size() - 1);
			f[i] = add(P, mov(Q, 1));
		}
	}
	for(int k = 1; k <= n; k ++)
		cout << (k < (int)f[1].size() ? f[1][k].val() : 0) << "\n";
}

标签:qolys,int,cdots,vector,solve,dp,abc269
From: https://www.cnblogs.com/zhangmj2008/p/abc269.html

相关文章

  • ABC269
    DContent给你若干个点和相邻点的定义,问你图中有几个连通块。Sol连通用并查集维护,就是这里的相邻有点怪。Code#includeusingnamespacestd;constint_=1005;int......