// Code By CloudySky #include<bits/stdc++.h> namespace IO { inlineintread(){ int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + (c ^ 48); c = getchar(); } return x * f; } voidprint_n(longlong x){ if (x > 9) print_n(x / 10); putchar(x % 10 + '0'); } inlinevoidprint(longlong x, char s = '\n'){ if (x < 0) putchar('-'), x = -x; print_n(x), putchar(s); } } // namespace IO usingnamespace IO; constint Maxn = 1e5 + 10; usingnamespace std;
int n, m, cnt[Maxn << 1], d[Maxn], id[Maxn], rk[Maxn]; structedge {int u, v;} e[Maxn << 1]; vector <int> G[Maxn], g[Maxn]; boolcmp(int x, int y){return d[x] == d[y] ? x > y : d[x] < d[y];}
// 不对任何边进行限制的方案数 longlongf0(){return1ll * n * (n - 1) * (n - 2) * (n - 3) / 24;} // 仅对一条边进行限制的方案数 longlongf1(){return1ll * m * (n - 2) * (n - 3) / 2;} // 对于 2 条边进行限制的方案数 longlongf2(){ longlong res = 0; // 两条边无交点 for (int i = 1; i <= m; ++i) res += 1ll * m - (d[e[i].u] + d[e[i].v] - 1); res /= 2; // 两条边有交点 for (int i = 1; i <= n; ++i) res += 1ll * (n - 3) * d[i] * (d[i] - 1) / 2; return res; } // 对于 3 条边进行限制的方案数 longlongf3(){ staticint vis[Maxn], c[Maxn]; longlong res = 0; // 3 条边构成 3 圆环 memset(vis, 0, sizeof(vis)), memset(c, 0, sizeof(c)); for (int i = 1, x, y; i <= n; ++i) { for (int x : G[i]) if (rk[i] > rk[x]) vis[x] = 1; for (unsigned j = 0; j < G[i].size(); ++j) if (rk[i] > rk[x = G[i][j]]) for (unsigned k = 0; k < G[x].size(); ++k) if (rk[x] > rk[y = G[x][k]] && vis[y]) ++res, ++cnt[g[x][k]], ++cnt[g[i][j]], ++c[y]; for (unsigned j = 0; j < G[i].size(); ++j) if (rk[i] > rk[x = G[i][j]]) cnt[g[i][j]] += c[x], vis[x] = c[x] = 0; } res = res * (n - 6); // 3 条边构成菊花 for (int i = 1; i <= n; ++i) res += 1ll * d[i] * (d[i] - 1) * (d[i] - 2) / 6; // 3 条边构成链 for (int i = 1; i <= m; ++i) res += 1ll * (d[e[i].u] - 1) * (d[e[i].v] - 1); return res; }
// 对于 4 条边进行限制的方案数 longlongf4(){ staticint vis[Maxn], c[Maxn]; longlong res = 0; // 4 条边构成 4 元环 memset(vis, 0, sizeof(vis)), memset(c, 0, sizeof(c)); for (int i = 1; i <= n; ++i) { for (int x : G[i]) if(rk[i] > rk[x]) vis[x] = 1; for (int x : G[i]) if (rk[i] > rk[x]) for (int y : G[x]) if (rk[x] > rk[y] && vis[y]) res += 1ll * d[i] + d[x] + d[y] - 6; for (int x : G[i]) vis[x] = 0; } // 4条边构成一个 3 元环带一个点 for (int i = 1; i <= n; ++i) { for (int x : G[i]) if (rk[i] > rk[x]) for (int y : G[x]) if (rk[i] > rk[y]) res += 1ll * c[y], ++c[y]; for (int x : G[i]) if (rk[i] > rk[x]) for (int y : G[x]) c[y] = 0; } return res; }
// 对于 5 条边进行限制的方案数 longlongf5(){ // 只有一种情况,两个三元环有一个公共边 longlong res = 0; for (int i = 1; i <= m; ++i) res += 1ll * cnt[i] * (cnt[i] - 1) / 2; return res; }
longlongAbs(longlong x){return x > 0 ? x : -x;}
signedmain(){ n = read(), m = read(); for (int i = 1, u, v; i <= m; ++i) u = read(), v = read(), ++d[u], ++d[v], G[u].push_back(v), G[v].push_back(u), g[u].push_back(i), g[v].push_back(i), e[i] = {u, v}; for (int i = 1; i <= n; ++i) id[i] = i; sort(id + 1, id + n + 1, cmp); for (int i = 1; i <= n; ++i) rk[id[i]] = i; print(-f0() + f1() - f2() + f3() - f4() + f5()); return0; }
// Code By CloudySky #include<bits/stdc++.h> #define int long long namespace IO { inlineintread(){ int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + (c ^ 48); c = getchar(); } return x * f; } voidprint_n(int x){ if (x > 9) print_n(x / 10); putchar(x % 10 + '0'); } inlinevoidprint(int x, char s = '\n'){ if (x < 0) putchar('-'), x = -x; print_n(x), putchar(s); } } // namespace IO usingnamespace IO; constint Maxn = 1e7 + 10; usingnamespace std; constint g[] = {0, 2, 16, 272, 7936, 353792}; int f[20][20][20], P, ch[30], inv[30], fac[Maxn];
intPow(int x, int y, int ans = 1){ for (; y; y >>= 1, x = x * x % P) if (y & 1) ans = ans * x % P; return ans; }
intC(int n, int m){ int ans = 1; for (int i = n - m + 1; i <= n; ++i) ans = ans * i % P; for (int i = 1; i <= m; ++i) ans = ans * inv[i] % P; return ans; }
signedmain(){ int n = read(), m = read(); P = read(); inv[1] = 1; for (int i = 2; i <= 3 * m; ++i) inv[i] = (P - P / i) * inv[P % i] % P; fac[0] = 1; for (int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * i % P; f[0][0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 1; j <= m; ++j) for (int k = 2 * j + 1; k <= 3 * m; ++k) for (int v = j; v <= m; ++v) f[i][k][v] = (f[i][k][v] + f[i - 1][k - 2 * j - 1][v - j] * C(k, 2 * j + 1) % P * g[j] % P) % P; } for (int i = 1; i <= m; ++i) { for (int j = 0; j <= i; ++j) { if (j & 1) ch[i] = (ch[i] + P - C(i, j) * Pow(i - j, m) % P) % P; else ch[i] = (ch[i] + C(i, j) * Pow(i - j, m) % P) % P; } } int ans = 0; for (int i = 1; i <= m; ++i) { for (int j = 1; j <= min(n, 3 * m); ++j) for (int k = 1; k <= m; ++k) ans = (ans + f[i][j][k] * C(n, j) % P * C(n - j + i, i) % P * ch[k] % P * fac[n - j] % P) % P; } print(ans * Pow(fac[n], P - 2) % P); return0; }
D3T1 拆分
题目描述
现有一整数 n,求满足以下条件的整数序列个数:
a1+a2+⋯+am=n
0<a1≤a2≤⋯≤am
∀i=j,∣ai−aj∣≥k
hmmodp=1
思路
不考虑 k 的限制的话 n2 整数拆分即可。
fi,j 表示划分了 i 段,总和为 j 的方案数。
转移的话因为单调不降,所以有两种方法,把前面所有数都加 1 和另开一段 1。
fi,j=fi,j−i,fi−1,j−1
对于 k 的限制,直接垫高补齐就行了(如果要拆分成 i 个数,那么只需要和为 n−2i×(i−1)×k)。反而可以消掉一些复杂度,使它满足 O(nn)。
// Code By CloudySky #include<bits/stdc++.h> // #define int long long namespace IO { inlineintread(){ int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + (c ^ 48); c = getchar(); } return x * f; } voidprint_n(int x){ if (x > 9) print_n(x / 10); putchar(x % 10 + '0'); } inlinevoidprint(int x, char s = '\n'){ if (x < 0) putchar('-'), x = -x; print_n(x), putchar(s); } } // namespace IO usingnamespace IO; constint Maxn = 1e6 + 10, P = 998244353; usingnamespace std; int h[Maxn], f[2][Maxn];
namespace Subtask0k { int sum[Maxn], g[2][Maxn];
intmain(int n){ int s = ceil(sqrt(n)), u = 0, ans = 0; f[0][0] = 1; for (int i = 1; i < s; ++i) { for (int j = i; j <= n; ++j) { f[0][j] = (f[0][j] + f[0][j - i]) % P; } } sum[0] = 1, g[0][0] = 1, u = 0; for (int i = 1; i * i <= n; ++i) { u ^= 1, memset(g[u], 0, sizeof(g[u])); for (int j = i * s; j <= n; ++j) { g[u][j] = (g[u][j - i] + g[u ^ 1][j - s]) % P; (sum[j] += g[u][j]) %= P; } } for (int i = 0; i <= n; ++i) { (ans += 1ll * sum[i] * f[0][n - i] % P) %= P; } return ans; }
} // namespace Subtask0k
signedmain(){ int n = read(), k = read(), p = read(), u = 0, ans = 0; for (int i = 0; i < p; ++i) h[i] = read(); if (k == 0) returnprint(h[0] == 0 ? 0 : Subtask0k::main(n)), 0; f[0][0] = 1; for (int i = 1, t = 0; i <= n - t; ++i, t = i * (i - 1) / 2 * k) { u ^= 1, memset(f[u], 0, sizeof(f[u])); for (int j = i; j <= n - t; ++j) { f[u][j] = (f[u ^ 1][j - 1] + f[u][j - i]) % P; } if (h[i % p]) ans = (ans + f[u][n - t]) % P; } print(ans); return0; }
voidchange(int p, int l, int r, int k){ if (l(p) >= l && r(p) <= r) { v(p) = t(p) = k; return; } spread(p); int mid = (l(p) + r(p)) >> 1; if (l <= mid) change(ls, l, r, k); if (r > mid) change(rs, l, r, k); v(p) = min(v(ls), v(rs)); }
intask(int p, int l, int r){ if (l(p) >= l && r(p) <= r) returnv(p); spread(p); int mid = (l(p) + r(p)) >> 1, ans = inf; if (l <= mid) ans = min(ans, ask(ls, l, r)); if (r > mid) ans = min(ans, ask(rs, l, r)); return ans; }
intFind(int p, int k){ if (l(p) == r(p)) returnl(p); spread(p); if (v(ls) <= k) returnFind(ls, k); elsereturnFind(rs, k); }
// Code By CloudySky #include<bits/stdc++.h> // #define int long long namespace IO { inlineintread(){ int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + (c ^ 48); c = getchar(); } return x * f; } voidprint_n(longlong x){ if (x > 9) print_n(x / 10); putchar(x % 10 + '0'); } inlinevoidprint(longlong x, char s = '\n'){ if (x < 0) putchar('-'), x = -x; print_n(x), putchar(s); } } // namespace IO usingnamespace IO; constint Maxn = 1.2e6 + 10; constlonglong inf = 1e18; usingnamespace std;
constint sz = 3;
structmat { longlong a[sz][sz]; mat () { for (int i = 0; i < sz; ++i) for (int j = 0; j < sz; ++j) a[i][j] = -inf; for (int i = 0; i < sz; ++i) a[i][i] = 0; } mat(int v) { for (int i = 0; i < sz; ++i) for (int j = 0; j < sz; ++j) a[i][j] = -inf; a[0][0] = a[1][0] = a[2][0] = 0ll, a[0][1] = a[1][2] = 1ll * v; } mat operator * (const mat &T) const { mat res; for (int i = 0; i < sz; ++i) { for (int j = 0; j < sz; ++j) for (int k = 0; k < sz; ++k) res.a[i][j] = max(res.a[i][j], a[i][k] + T.a[k][j]); } return res; } };
int a[Maxn], s = 34;
structStree { int l, r; mat v; #define l(x) St[x].l #define r(x) St[x].r #define v(x) St[x].v } St[150010];
#define ls p << 1 #define rs p << 1 | 1
mat bf(int l, int r, mat res = mat()){ for (int i = l; i <= r; ++i) res = res * mat(a[i]); return res; }
voidbuild(int p, int l, int r){ l(p) = l, r(p) = r; if (r - l + 1 <= s) returnv(p) = bf(l, r), void(); int mid = (l + r) >> 1; build(ls, l, mid), build(rs, mid + 1, r); v(p) = v(ls) * v(rs); }
voidchange(int p, int v, int k){ if (r(p) - l(p) + 1 <= s) return a[v] = k, v(p) = bf(l(p), r(p)), void(); int mid = (l(p) + r(p)) >> 1; if (v <= mid) change(ls, v, k); elsechange(rs, v, k); v(p) = v(ls) * v(rs); }
mat ask(int p, int l, int r){ if (l(p) >= l && r(p) <= r) returnv(p); if (r(p) - l(p) + 1 <= s) returnbf(max(l, l(p)), min(r, r(p))); int mid = (l(p) + r(p)) >> 1; mat ans; if (l <= mid) ans = ans * ask(ls, l, r); if (r > mid) ans = ans * ask(rs, l, r); return ans; }
longlongas(int l, int r, longlong res = 0){ mat ans = ask(1, l, r); for (int i = 0; i < sz; ++i) res = max(res, ans.a[0][i]); return res; }
signedmain(){ freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); int n = read(), m = read(); for (int i = 1; i <= n; ++i) a[i] = read(); build(1, 1, n); for (int i = 1; i <= m; ++i) { int op = read(), l, r, x, y; if (op == 1) l = read(), r = read(), print(as(l, r)); if (op == 2) x = read(), y = read(), change(1, x, y); } return0; }