加训

  • 写了部分分做法,已补
  • 已补
  • 写了部分分做法,未补
  • 鸽子
  • \(22.08.12,13,14,15,16\):回忆了一些题目并记在奇怪的地方了,停更
  • \(22.08.17\):和忙仔一起写 \(cf\) 签到结果 \(\text{unordered_map}\) 被卡了,把解决问题的代码放在仙人板板里了。
  • \(22.08.29,31\):做了几个 \(cf\) 签到题,自闭了。、
场次/日期 T1 T2 T3
\(22.08.05\) \(\text{树}\) \(\text{山河重整}\) \(\text{排列}\)
\(22.08.12\) \(\text{TRIPWAYS}\)
\(22.08.14\) \(\text{新年的军队}\)
\(22.08.17\) \(\text{多项式欧几里得}\) \(\text{冬至}\)

题解

考虑记 \(f_{i,j,k}\) 表示处理到标号 \(i\),第一棵树 \(2\)~\(i\) 中的非叶子数量为 \(j\),第二棵树 \(i+1\)~\(n-1\) 中的非叶子数量为 \(k\) 的方案数,转移的时候扣掉不合法方案数即可。
代码链接

山河重整

题解

60分做法:
发现记 \(f_{i,j}\) 表示从 \(1,2...i\) 选出的集合,恰凑出 \(1,2...j\) 的方案数。
发现其实 \(j\) 就是我们选出的集合所有数之和, \(f_{i-1,j}\rightarrow f_{i,j+i}\) 这个转移成立当且仅当 \(j\ge i-1\)
写的时候 \(j\)\(n\) 取个 \(\text{min}\) 就能 \(O(n^2)\)


发现 \(\text{EI}\) 的博客里有一句话谈到的意思是 \(\sum\limits_{i}f_{t,i}=2^t\),这样就不用将 \(j,n\)\(\text{min}\) 了,直接用 \(2^n-\sum\limits_{i=0}^{n-1}f_{n,i}\) 就是答案。

其实这也相当于是 \(2^n-\sum\limits_{i=0}^{n-1}2^{n-(i+1)}f_{i+1,i}\)
改写成 \(2^n-\sum\limits_{i=1}^n2^{n-i}F_i\)\(F_i\) 表示恰凑不出 \(i\) 的集合数。
这样一来就有 \(x(1+x)(1+x^2)\cdots=\sum\limits_{i\ge1}F_ix^i(1+x^{i+1})\cdots\)

\[\begin{aligned} F(x^k)=&\prod\limits_{i\ge k}(1+x^i)\\ F(x^{k})=&F(x^{k+1})(1+x^{k})\\ 令q=&x^k\\ 即F(q)=&(1+q)F(qx)\\ [q^n]F(q)=&[q^n]F(qx)+[q^{n-1}]F(qx)\\ =&x^n[q^n]F(q)+qx^{n-1}[q^{n-1}]F(q)\\ \Rightarrow [q^n]F(q)=&\frac{x^{n-1}}{1-x^n}[qx^{n-1}]F(q)\\ 而[q^0]F(q)=&1\\ \Rightarrow [q^n]F(q)=&\frac{q^nx^{n(n-1)/2}}{\prod\limits_{i=1}^{n}(1-x^i)}\\ \Rightarrow F(x^k)=&\sum\limits_{t\ge0}\frac{x^{\frac{t(t-1)}2+tk}}{\prod\limits_{i=1}^t(1-x^i)}\\ x(1+x)(1+x^2)\cdots=&\sum\limits_{t\ge0}A(x^{t+1})\frac{x^{\frac{t(t+1)}2}}{\prod\limits_{i=1}^t(1-x^i)}\\ 其中A(x)=&\sum\limits_{i\ge1}a_ix^i \end{aligned} \]

倍增算即可
代码链接


TRIPWAYS

这是一份分式分解的板子。

多项式取模一定要写小范围暴力不然是啥笔
#include <bits/stdc++.h>
#define gc getchar
using namespace std;
typedef long long ll;
inline int read() {
	static int ans, f;
	static char ch;
	for (f = 1, ch = gc(); !isdigit(ch); f ^= ch == '-', ch = gc());
	for (ans = 0; isdigit(ch); ans = (((ans << 2) + ans) << 1) + (ch ^ 48), ch = gc());
	return f ? ans : -ans;
}
inline ll readl() {
	static ll ans;
	static int f;
	static char ch;
	for (f = 1, ch = gc(); !isdigit(ch); f ^= ch == '-', ch = gc());
	for (ans = 0; isdigit(ch); ans = (((ans << 2) + ans) << 1) + (ch ^ 48), ch = gc());
	return f ? ans : -ans;
}
namespace modular {
	const int mod = 1e9 + 7;
	inline int add(int a, int b) { return a < mod - b ? a + b : a - mod + b; }
	inline int dec(int a, int b) { return a < b ? a - b + mod : a - b; }
	inline int mul(int a, int b) { return (ll) a * b % mod; }
	inline void Add(int &a, int b) { a = a < mod - b ? a + b : a - mod + b; }
	inline void Dec(int &a, int b) { a = a < b ? a - b + mod : a - b; }
	inline void Mul(int &a, int b) { a = (ll) a * b % mod; }
	inline int ksm(int a, int p) {
		static int res;
		for (res = 1; p; p >>= 1, Mul(a, a)) if (p & 1) Mul(res, a);
		return res;
	}
	inline int Inv(int a) { return ksm(a, mod - 2); }
}	using namespace modular;
#define pb push_back
#define rez resize
typedef double db;
struct cp {
	db x, y;
	cp(db _x = 0, db _y = 0) : x(_x), y(_y) {}
	inline cp operator ~() const { return cp(x, -y); }
};
typedef vector <cp> moly;
typedef vector <int> poly;
inline cp operator + (cp a, cp b) { return cp(a.x + b.x, a.y + b.y); }
inline cp operator - (cp a, cp b) { return cp(a.x - b.x, a.y - b.y); }
inline cp operator * (cp a, db b) { return cp(a.x * b, a.y * b); }
inline cp operator * (db a, cp b) { return cp(a * b.x, a * b.y); }
inline cp operator * (cp a, cp b) { return cp(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
inline void operator += (cp &a, cp b) { a.x += b.x, a.y += b.y; }
inline void operator -= (cp &a, cp b) { a.x -= b.x, a.y -= b.y; }
inline void operator *= (cp &a, db b) { a.x *= b, a.y *= b; }
inline void operator /= (cp &a, db b) { a.x /= b, a.y /= b; }
const db pi = acos(-1.0);
const int N = 4005;
int n, m, Q, a[N], f[N][N], b[N], fac[N], ifac[N];
vector <int> e[N];
poly tr[N << 2];
int lim, tim;
moly w[22];
poly rev[22];
inline void init_w() {
	int lm = 1 << 20;
	w[20].rez(lm);
	for (int i = 0; i < lm; ++i) w[20][i] = cp(cos(pi / lm * i), sin(pi / lm * i));
	for (int i = 19; ~i; --i) {
		w[i].rez(lm >>= 1);
		for (int j = 0; j < lm; ++j) w[i][j] = w[i + 1][j << 1];
	}
}
inline void init_r(int up) {
	for (lim = 1, tim = 0; lim < up; lim <<= 1, ++tim);
	if (rev[tim].size()) return;
	rev[tim].rez(lim);
	for (int i = 1; i < lim; ++i) rev[tim][i] = (rev[tim][i >> 1] >> 1) | ((i & 1) << (tim - 1));
}
inline int C(int n, int m) { return n < m || m < 0 ? 0 : mul(fac[n], mul(ifac[m], ifac[n - m])); }
inline void init_fac() {
	fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
	for (int i = 2; i <= 4000; ++i) fac[i] = mul(fac[i - 1], i);
	ifac[4000] = Inv(fac[4000]);
	for (int i = 3999; i > 1; --i) ifac[i] = mul(ifac[i + 1], i + 1);
}
inline void fft(moly &a, int typ) {
	static cp a0, a1;
	for (int i = 0; i < lim; ++i) if (i < rev[tim][i]) swap(a[i], a[rev[tim][i]]);
	for (int i = 1, t = 0; i < lim; i <<= 1, ++t) for (int j = 0; j < lim; j += i << 1) {
		for (int k = 0; k < i; ++k) {
			a0 = a[j + k], a1 = a[j + k + i] * w[t][k];
			a[j + k] = a0 + a1;
			a[j + k + i] = a0 - a1;
		}
	}
	if (~typ) return;
	reverse(++a.begin(), a.end());
	for (int i = 0; i < lim; ++i) a[i] /= (db)lim;
}
const int Bas = (1 << 15) - 1;
inline poly operator * (poly a, poly b) {
	int n = a.size(), m = b.size(), t = n + m - 1;
	if (!n || !m) return poly(0);
	poly c(t);
	if (n <= 50 || m <= 50) {
		for (int i = 0; i < n; ++i) if (a[i])
		for (int j = 0; j < m; ++j) if (b[j])
		Add(c[i + j], mul(a[i], b[j]));
		return c;
	}
	init_r(t);
	moly A(lim), B(lim), P(lim), Q(lim);
	for (int i = 0; i < lim; ++i) {
		if (i < n) A[i] = cp(a[i] >> 15, a[i] & Bas);
		else A[i] = cp();
		if (i < m) B[i] = cp(b[i] >> 15, b[i] & Bas);
		else B[i] = cp();
	}
	fft(A, 1), fft(B, 1);
	cp cur[4];
	for (int i = 0, j = 0; i < lim; ++i, j = j ? j - 1 : lim - 1) {
		cur[0] = (A[i] + (~A[j])) * cp(0.5, 0);
		cur[1] = (~(A[j]) - A[i]) * cp(0, 0.5);
		cur[2] = (B[i] + (~B[j])) * cp(0.5, 0);
		cur[3] = ((~B[j]) - B[i]) * cp(0, 0.5);
		P[i] = cur[0] * cur[2] + cp(0, 1) * cur[1] * cur[3];
		Q[i] = cur[0] * cur[3] + cp(0, 1) * cur[1] * cur[2];
	}
	fft(P, -1), fft(Q, -1);
	ll cr[4];
	for (int i = 0; i < t; ++i) {
		cr[0] = (ll)(P[i].x + 0.5) % mod;
		cr[1] = (ll)(P[i].y + 0.5) % mod;
		cr[2] = (ll)(Q[i].x + 0.5) % mod;
		cr[3] = (ll)(Q[i].y + 0.5) % mod;
		c[i] = (((cr[0] << 30) + cr[1] + ((cr[2] + cr[3]) << 15)) % mod + mod) % mod;
	}
	return c;
}
inline poly poly_inv(poly a, int k) {
	int n = a.size();
	poly b(k), c;
	b[0] = Inv(a[0]);
	for (int i = 1, l = 2; i < k; i <<= 1, l <<= 1) {
		c.rez(l);
		for (int j = 0; j < l; ++j) c[j] = j < n ? a[j] : 0;
		c = c * b, c.rez(l);
		for (int j = 0; j < l; ++j) c[j] = dec(j ? 0 : 2, c[j]);
		b = b * c, b.rez(l);
	}
	return b.rez(k), b;
}
inline poly operator / (poly a, poly b) {
	int n = a.size(), m = b.size(), t = n - m + 1;
	reverse(a.begin(), a.end()), reverse(b.begin(), b.end());
	a.rez(t), a = a * poly_inv(b, t);
	return a.rez(t), reverse(a.begin(), a.end()), a;
}
inline poly operator - (poly a, poly b) {
	int n = b.size();
	if ((int) a.size() < n) a.rez(n);
	for (int i = 0; i < n; ++i) Dec(a[i], b[i]);
	return a;
}
inline poly operator + (poly a, poly b) {
	int n = b.size();
	if ((int) a.size() < n) a.rez(n);
	for (int i = 0; i < n; ++i) Add(a[i], b[i]);
	return a;
}
inline poly operator % (poly a, poly b) {
	int n = (int) a.size(), m = (int) b.size();
	if (n < m) return a;
	if (m <= 50) {
		int iv = Inv(b.back());
		for (int i = 0; i < m; ++i) Mul(b[i], iv);
		for (int i = n - 1; i >= m - 1; --i) {
			for (int j = i - 1, k = m - 2; k >= 0; --k, --j) Dec(a[j], mul(a[i], b[k]));
			a[i] = 0;
		}
		return a.rez(m - 1), a;
	}
	a = a - (a / b) * b;
	return a.rez(m - 1), a;
}
#define lc (p << 1)
#define rc (p << 1 | 1)
inline void build(int p, int l, int r) {
	if (l == r) {
		tr[p].rez(b[l] + 1);
		for (int coe, i = 0, pw = 1; i <= b[l]; ++i, Mul(pw, dec(0, a[l]))) {
			coe = mul(C(b[l], i), pw);
			tr[p][i] = coe;
		}
		return;
	}
	int mid = (l + r) >> 1;
	build(lc, l, mid), build(rc, mid + 1, r);
	tr[p] = tr[lc] * tr[rc];
}
poly F, vl[N], tp;
// x --> (1-x) * a  a_j * bas^j * C(j, i) --> b_i 
inline poly trans1(poly a, int bas, int k) {
	if (k <= 50) {
		poly b(k);
		for (int i = 0, pw = 1; i < k; ++i, Mul(pw, bas)) if (a[i])
		for (int j = 0; j <= i; ++j) Add(b[j], mul(mul(pw, a[i]), C(i, j)));
		for (int i = 0; i < k; ++i) if (i & 1) b[i] = dec(0, b[i]);
		return b;
	}
	a.rez(k), tp.rez(k);
	for (int i = 0, pw = 1; i < k; ++i, Mul(pw, bas)) {
		Mul(a[i], mul(pw, fac[i]));
 		tp[i] = ifac[i];
	}
	reverse(a.begin(), a.end());
	a = a * tp, a.rez(k);
	reverse(a.begin(), a.end());
	for (int i = 0; i < k; ++i) {
		Mul(a[i], ifac[i]);
		if (i & 1) a[i] = dec(0, a[i]);
	}
	return a;
}
//x --> 1 + ax
inline poly trans2(poly a, int bas, int k) {
	if (k <= 50) {
		poly b(k);
		for (int i = 0; i < k; ++i) if (a[i])
		for (int j = 0; j <= i; ++j) Add(b[j], mul(a[i], C(i, j)));
		for (int i = 0, pw = 1; i < k; ++i, Mul(pw, bas)) Mul(b[i], pw);
		return b;
	}
	a.rez(k), tp.rez(k);
	for (int i = 0; i < k; ++i) {
		Mul(a[i], fac[i]);
		tp[i] = ifac[i];
	}
	reverse(a.begin(), a.end());
	a = a * tp, a.rez(k);
	reverse(a.begin(), a.end());
	for (int i = 0, pw = 1; i < k; ++i, Mul(pw, bas)) {
		Mul(a[i], ifac[i]);
		Mul(a[i], pw);
	}
	return a;
}
inline void solve(int p, int l, int r, poly f1, poly f2) {
	if (l == r) {
		int iv = Inv(a[l]);
		poly tp = F % tr[p];
		vl[l] = trans1(f1, iv, b[l]) * poly_inv(trans1(f2, iv, b[l]), b[l]);
		vl[l].rez(b[l]);
		vl[l] = trans2(vl[l], dec(0, a[l]), b[l]);
		return;
	}
	int mid = (l + r) >> 1;
	solve(lc, l, mid, f1 % tr[lc], ((tr[rc] % tr[lc]) * (f2 % tr[lc])) % tr[lc]);
	solve(rc, mid + 1, r, f1 % tr[rc], ((tr[lc] % tr[rc]) * (f2 % tr[rc])) % tr[rc]);
	return;
}
int Pw1[N][1001], Pw2[N][1001], Pw3[N][1001];
inline void init_Pw() {
	for (int i = 1; i <= m; ++i) {
		Pw1[i][0] = 1;
		for (int j = 1; j <= 1000; ++j) Pw1[i][j] = mul(Pw1[i][j - 1], a[i]);
		Pw2[i][0] = 1;
		for (int j = 1; j <= 1000; ++j) Pw2[i][j] = mul(Pw2[i][j - 1], Pw1[i][1000]);
		Pw3[i][0] = 1;
		for (int j = 1; j <= 1000; ++j) Pw3[i][j] = mul(Pw3[i][j - 1], Pw2[i][1000]);
	}
}
inline int getpw(int id, int k) { return mul(Pw3[id][k / 1000000], mul(Pw2[id][k / 1000 % 1000], Pw1[id][k % 1000])); }
int Mt[N];
inline void cal(ll l, ll r, int m) {
	static int mt[N], tp;
	int ps = -1;
	if (!m) {
		for (ll x = l; x <= r; ++x) Mt[++ps] = 1;
		return;
	}
	tp = 0;
	int cur = 1;
	mt[0] = 1;
	for (ll x = l; x <= r; ++x) {
		cur = cur * (x % mod) % mod;
		if (!tp) {
			cur = 1;
			for (int i = 1; i <= m; ++i) mt[i] = mt[i - 1] * ((x - i + 1) % mod) % mod;
			tp = m;
		}
		Mt[++ps] = mul(mt[tp], cur);
		--tp;
	}
}
int main() {
	#ifdef ldxcaicai
	freopen("lx.in", "r", stdin);
	#endif
	n = read(), m = read(), Q = read();
	init_w();
	init_fac();
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 1, u, v; i <= m; ++i) {
		u = read(), v = read();
		e[u].pb(v);
	}
	f[0][1] = 1;
	for (int tim = 1; tim <= n; ++tim) {
		for (int i = 1; i <= n; ++i) if (f[tim - 1][i]) {
			Add(f[tim][i], mul(f[tim - 1][i], a[i]));
			for (int j = 0; j < (int) e[i].size(); ++j)
			Add(f[tim][e[i][j]], f[tim - 1][i]);
		}
	}
	m = 0;
	sort(a + 1, a + n + 1);
	for (int i = 1; i <= n; ++i) {
		if (!m || a[m] != a[i]) a[++m] = a[i], b[m] = 1;
		else ++b[m];
	}
	F.rez(n + 1);
	for (int i = 0; i < n; ++i) F[i] = f[i][n];
	build(1, 1, m);
	F = F * tr[1], F.rez(n);
    solve(1, 1, m, F % tr[1], poly(1, 1));
	init_Pw(); 
	for (int tt = 1; tt <= Q; ++tt) {
		ll k = readl();
		if (k <= n) {
			cout << f[k][n] << '\n';
			continue;
		}
		int res = 0;
		for (int id = 1; id <= m; ++id) {
			cal(k, k + b[id] - 1, b[id] - 1);
			for (int i = b[id] - 1, pw = ksm(a[id], (k - i) % (mod - 1)), coe; ~i; --i, Mul(pw, a[id])) {
				coe = mul(vl[id][i], mul(ifac[b[id] - 1], mul(pw, Mt[b[id] - 1 - i])));
				Add(res, coe);
			}
		}
		cout << res << '\n';
	}
	return 0;
}

多项式欧几里得

看这篇学的

没有加优化,目前速度榜 $\text{rk4}$:
inline pir poly_div(poly a, poly b) {
	static poly c;
	int n = a.size(), m = b.size();
	if (n < m) return pir(poly(0), a);
	c = a / b;
	return pir(c, fix(a - b * c));
}
inline poly operator % (poly a, poly b) { return poly_div(a, b).se; }
struct mat {
	poly a[2][2];
	mat() { a[0][0] = a[0][1] = a[1][0] = a[1][1] = poly(0); }
	inline poly * operator [] (const int &k) { return a[k]; }
} O, I, S;
inline mat operator * (mat a, mat b) {
	mat c;
	c[0][0] = fix(a[0][0] * b[0][0] + a[0][1] * b[1][0]);
	c[0][1] = fix(a[0][0] * b[0][1] + a[0][1] * b[1][1]);
	c[1][0] = fix(a[1][0] * b[0][0] + a[1][1] * b[1][0]);
	c[1][1] = fix(a[1][0] * b[0][1] + a[1][1] * b[1][1]);
	return c;
}
inline void trans(mat A, poly &a, poly &b) {
	static poly _a, _b;
	_a = fix(A[0][0] * a + A[0][1] * b);
	_b = fix(A[1][0] * a + A[1][1] * b);
	a = _a, b = _b, _a.rez(0), _b.rez(0);
}
inline mat hgcd(poly a, poly b) {
	int n = a.size(), m = b.size(), mid = (n + 1) / 2;
	if (m <= mid) return I;
	mat res, M;
	poly a0 = poly(a.begin() + mid, a.end()), b0 = poly(b.begin() + mid, b.end());
	trans(res = hgcd(a0, b0), a, b);
	if ((int) b.size() <= mid) return res;
	pir tp = poly_div(a, b);
	M = S, M[1][1] -= tp.fi;
	res = M * res;
	if ((int) tp.se.size() <= mid) return res;
	mid = 2 * mid - (int) tp.se.size();
	a0 = poly(b.begin() + mid, b.end()), b0 = poly(tp.se.begin() + mid, tp.se.end());
	return hgcd(a0, b0) * res;
}
inline mat cogcd(poly a, poly b) {
	if (!(int) b.size()) {
		mat res = I;
		return res[0][0][0] = Inv(a[0]), res;
	}
	mat M = hgcd(a, b), Q;
	trans(M, a, b);
	pir tp = poly_div(a, b);
	Q = S, Q[1][1] -= tp.fi;
	return cogcd(b, tp.se) * Q * M;
}

冬至

整了个带矩阵奇怪做法,有空记录一下。
被特征多项式和容斥暴打了,因为 \(\text{hdu}\) 上一直卡常加了很多毒瘤优化。

Code
const int N = 2e5 + 5;
int f[N], fac[N], ifac[N], inv[N];
int n, m;
inline int C(int n, int m) { return n < m || m < 0 ? 0 : mul(fac[n], mul(ifac[m], ifac[n - m]));; }
inline mat solve(int l, int r) {
    if (l == r) {
        mat res;
        res[0][0] = poly(2);
        res[0][0][0] = dec(1, inv[l]);
        res[0][0][1] = inv[l];
        res[0][1] = poly(2);
        res[0][1][1] = mod - inv[l];
        res[1][0] = poly(1, 1);
        return res;
    }
    int mid = (l + r) >> 1;
    return solve(mid + 1, r) * solve(l, mid);
}
int main() {
    #ifdef ldxcaicai
    freopen("lx.in", "r", stdin);
    #endif
    init_w();
	m = read(), n = read();
    fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
    for (int i = 2; i <= n; ++i) fac[i] = mul(fac[i - 1], i);
    ifac[n] = Inv(fac[n]);
    for (int i = n - 1; i > 1; --i) ifac[i] = mul(ifac[i + 1], i + 1);
    for (int i = 1; i <= n; ++i) inv[i] = mul(ifac[i], fac[i - 1]);
	poly F(2), G, coe(n + 1);
	F[0] = n, F[1] = mod - 1, 
	trans(solve(2, n), F, G);
	F.rez(n + 1), G.rez(n + 1);
	for (int i = 0; i <= n; ++i) coe[i] = mul(fac[n], dec(G[n - i], F[n - i]));
	for (int i = f[0] = 1; i < n; ++i) f[i] = mul(f[i - 1], n);
	for (int i = 1; i <= n; ++i) Dec(f[n], mul(f[n - i], coe[i]));
	Dec(f[n], fac[n]);
	--m;
	reverse(coe.begin(), coe.end());
	poly res = poly(1, 1), a = poly(2);
	a[1] = 1;
	for (; m; m >>= 1, a = fix(a * a % coe)) if (m & 1) res = fix(res * a % coe);
	res.rez(n);
	int ss = 0;
	for (int i = 0; i < n; ++i) Add(ss, mul(f[i + 1], res[i]));
	cout << ss << '\n';
    return 0;
}

CF1707 ABCD一句话题解

\(A:\) 倒着做看上去很对, \(O(n)\) 贪心。
\(B:\) 直接模拟,但是要特殊处理值为 \(0\) 的,看上去很对。
然后被拉去干活, \(C,D\) 都是赛后抽空签掉的、、、
\(C:\) 把最小生成树建出来,然后每条非树边都对可选点进行了限制,用树上差分取并即可。
\(D:\) 先容斥一下变成求不超过 \(k\) 次的答案,然后记 \(f_{i,j}\) 表示子树 \(i\) 中被删掉的节点的被删掉时间最大值为 \(j\) 的方案数,转移显然。

posted @ 2021-06-22 23:58  soroboruo  阅读(121)  评论(1编辑  收藏  举报