加训
- 会
- 写了部分分做法,已补
- 已补
- 写了部分分做法,未补
- 鸽子
- \(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\)
设
倍增算即可
代码链接
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\) 的方案数,转移显然。