完美的队列:
如果能求出每个加入的数在所有队列中都被移出去的时刻,那就可以很方便地计算答案了。
对序列分块,先考虑整块的,更新跨过整个块的区间答案,记 bi b i 表示队列要弹出当前的数需要的容量,那么每次操作实际上是对 bi b i 进行区间减法,注意到大部分时候是对整块打标记,如果不是整块打标记直接暴力就行了。当 所有 bi<0 b i < 0 的时候,就是所有东西都被弹出去的时候,可以利用双指针更新答案。
离散的块实际上也可以类似处理,预处理跨过整块的东西的前缀和,同样枚举每个位置和跨过它的区间,然后类似整块也可以双指针求出答案,这部分细节详见代码。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 100005;
const int B = 325;
const int inf = 0x3f3f3f3f;
int n, m, ans, a[N], b[N], f[N], l[N], r[N], x[N], all[N], sum[N], pos[N], qry[N];
vector <int> v[N];
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m);
for (int i = 1; i <= n; ++i) {
Read(a[i]);
}
for (int i = 1; i <= m; ++i) {
Read(l[i]), Read(r[i]), Read(x[i]);
}
for (int L = 1, R; L <= n; L += B) {
R = min(L + B - 1, n);
int val = -inf, tag = 0, cnt = 0, tot = 0;
for (int i = L; i <= R; ++i) {
b[i] = a[i], CheckMax(val, b[i]);
}
for (int i = 1, j = 2; i <= m; ++i) {
if (i > 1 && val + tag <= 0) {
if (l[i] <= L && R <= r[i]) {
++tag;
} else if (l[i] <= R && L <= r[i]) {
val = -inf;
for (int k = L; k <= R; ++k) {
if (k >= l[i] && k <= r[i]) {
++b[k];
}
CheckMax(val, b[k]);
}
}
}
for (; val + tag > 0 && j <= m; ++j) {
if (l[j] <= L && R <= r[j]) {
--tag;
} else if (l[j] <= R && L <= r[j]) {
val = -inf;
for (int k = L; k <= R; ++k) {
if (k >= l[j] && k <= r[j]) {
--b[k];
}
CheckMax(val, b[k]);
}
}
}
sum[i] = sum[i - 1];
if (l[i] <= L && R <= r[i]) {
CheckMax(f[i], val + tag > 0 ? m + 1 : j - 1);
++sum[i], all[++tot] = i;
} else if (l[i] <= R && L <= r[i]) {
qry[++cnt] = i, pos[cnt] = tot;
}
}
for (int i = L; i <= R; ++i) {
for (int j = 1, k = 2, val = a[i]; j <= cnt; ++j) {
if (j > 1) {
val += sum[qry[j]] - sum[qry[j - 1]];
if (l[qry[j]] <= i && i <= r[qry[j]]) {
++val;
}
}
for (; val > 0 && k <= cnt; ++k) {
val -= sum[qry[k]] - sum[qry[k - 1]];
if (l[qry[k]] <= i && i <= r[qry[k]]) {
--val;
}
}
if (l[qry[j]] <= i && i <= r[qry[j]]) {
if (val > 0) {
CheckMax(f[qry[j]], sum[m] - sum[qry[cnt]] < val ? m + 1 : all[pos[cnt] + val]);
} else {
CheckMax(f[qry[j]], l[qry[k - 1]] <= i && i <= r[qry[k - 1]] ? val ? all[pos[k - 1] + val + 1] : qry[k - 1] : all[pos[k - 1] + val]);
}
}
}
}
}
memset(sum, 0, sizeof sum);
for (int i = 1; i <= m; ++i) {
if (!sum[x[i]]++) {
++ans;
}
v[f[i]].pb(x[i]);
for (auto x : v[i]) {
if (!--sum[x]) {
--ans;
}
}
printf("%d\n", ans);
}
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
完美的集合:
注意到合法的关键点连成了一棵树,所以可以容斥,用 i i 合法的减去 和 pari p a r i 都合法的。
枚举之后将树处理出来,变成了一棵有根树,可以利用DFS序DP求出最大权值以及方案数。
剩下就是组合数取模的问题了,就是要快速求 ∏1≤i≤n,imod5≠0i ∏ 1 ≤ i ≤ n , i mod 5 ≠ 0 i ,考虑维护一个多项式 fn(x)=∏1≤i≤n,imod5≠0(x+i) f n ( x ) = ∏ 1 ≤ i ≤ n , i mod 5 ≠ 0 ( x + i ) ,然后找到一个最大的 k k 满足 ,那么考虑计算 f10k(x) f 10 k ( x ) ,剩下的暴力乘上去。 f10k(x)=f5k(x)+f5k(x+5k) f 10 k ( x ) = f 5 k ( x ) + f 5 k ( x + 5 k ) ,而注意到每次展开 f(x+5k) f ( x + 5 k ) 的时候,到了 23 23 项之后它的贡献就变成 0 0 了,所以多项式次数不超过 ,暴力维护就行了。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 65;
const int M = 10005;
const LL mod = 11920928955078125;
LL ans, lim, val_max, pwd[N], c[N][N], f[N][M], g[N][M];
int n, m, k, tim, v[N], w[N], dfn[N], seq[N], siz[N];
vector <pii> adj[N];
bool b[N];
inline LL Qul(LL x, LL y) {
return (__int128)x * y % mod;
}
inline LL Qow(LL x, LL y) {
LL r = 1;
for (; y; y >>= 1, x = Qul(x, x)) {
if (y & 1) {
r = Qul(r, x);
}
}
return r;
}
struct Poly {
LL a[N];
Poly() {
for (int i = 0; i < 23; ++i) {
a[i] = 0;
}
}
Poly operator * (const Poly &b) const {
Poly c;
for (int i = 0; i < 23; ++i) {
for (int j = 0; j <= i; ++j) {
c.a[i] = (c.a[i] + Qul(a[j], b.a[i - j])) % mod;
}
}
return c;
}
inline Poly Extend(LL x) {
Poly b;
pwd[0] = 1;
for (int i = 1; i < 23; ++i) {
pwd[i] = Qul(pwd[i - 1], x);
}
for (int i = 0; i < 23; ++i) {
for (int j = i; j < 23; ++j) {
b.a[i] = (Qul(a[j], Qul(pwd[j - i], c[j][i])) + b.a[i]) % mod;
}
}
return b;
}
};
map <LL, Poly> h;
inline Poly G(LL n) {
if (h.find(n) != h.end()) {
return h[n];
}
Poly r, t;
r.a[0] = 1;
if (n <= 20) {
for (int i = 1; i <= n; ++i) {
if (i % 5) {
t.a[0] = i, t.a[1] = 1, r = r * t;
}
}
} else {
LL val = n / 2 / 5 * 5;
Poly u = G(val - 1), v = u.Extend(val);
r = u * v;
for (LL i = val << 1; i <= n; ++i) {
if (i % 5) {
t.a[0] = i, t.a[1] = 1, r = r * t;
}
}
}
return h[n] = r;
}
inline LL F(LL n) {
LL r = 1;
for (LL i = 1; i <= n; i *= 5) {
r = Qul(r, G(n / i).a[0]);
}
return r;
}
inline LL C(LL x, LL y) {
if (x < y) {
return 0;
}
int c = 0;
for (LL i = 5; i <= x; i *= 5) {
c += x / i - y / i - (x - y) / i;
}
if (c >= 23) {
return 0;
}
LL r = 1;
for (int i = 1; i <= c; ++i) {
r = 5 * r % mod;
}
return Qul(Qul(r, F(x)), Qow(Qul(F(y), F(x - y)), mod / 5 * 4 - 1));
}
inline void Build(int x, int p, LL d) {
if (v[x] && d >= (lim + v[x] - 1) / v[x]) {
b[x] = false;
return ;
}
for (auto e : adj[x]) {
if (e.X != p) {
Build(e.X, x, d + e.Y);
}
}
}
inline void DFS(int x, int p) {
seq[dfn[x] = ++tim] = x, siz[x] = 1;
for (auto e : adj[x]) {
int y = e.X;
if (y != p && b[y]) {
DFS(y, x), siz[x] += siz[y];
}
}
}
inline void DP() {
for (int i = tim; i; --i) {
int x = seq[i];
for (int j = 0; j <= m; ++j) {
if (j < w[x]) {
f[x][j] = f[seq[i + siz[x]]][j], g[x][j] = g[seq[i + siz[x]]][j];
} else {
if (f[seq[i + siz[x]]][j] > f[seq[i + 1]][j - w[x]] + v[x]) {
f[x][j] = f[seq[i + siz[x]]][j];
g[x][j] = g[seq[i + siz[x]]][j];
} else if (f[seq[i + siz[x]]][j] < f[seq[i + 1]][j - w[x]] + v[x]) {
f[x][j] = f[seq[i + 1]][j - w[x]] + v[x];
g[x][j] = g[seq[i + 1]][j - w[x]];
} else {
f[x][j] = f[seq[i + siz[x]]][j];
g[x][j] = g[seq[i + siz[x]]][j] + g[seq[i + 1]][j - w[x]];
}
}
}
}
}
inline pair <LL, LL> Solve(int x) {
tim = 0, DFS(x, 0), seq[tim + 1] = 0, DP(), --g[x][0];
LL u = 0, v = 0;
for (int i = 0; i <= m; ++i) {
if (CheckMax(u, f[x][i])) {
v = g[x][i];
} else if (u == f[x][i]) {
v += g[x][i];
}
}
return mp(u, v);
}
inline pair <LL, LL> Solve(int x, int y) {
tim = 0, DFS(x, y), seq[tim + 1] = 0, DP(), --g[x][0];
tim = 0, DFS(y, x), seq[tim + 1] = 0, DP(), --g[y][0];
for (int i = 1; i <= m; ++i) {
if (CheckMax(f[x][i], f[x][i - 1])) {
g[x][i] = g[x][i - 1];
} else if (f[x][i] == f[x][i - 1]) {
g[x][i] += g[x][i - 1];
}
}
LL u = 0, v = 0;
for (int i = 0; i <= m; ++i) {
if (CheckMax(u, f[x][i] + f[y][m - i])) {
v = g[x][i] * g[y][m - i];
} else if (u == f[x][i] + f[y][m - i]) {
v += g[x][i] * g[y][m - i];
}
}
return mp(u, v);
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m), Read(k), Read(lim), ++lim, g[0][0] = 1;
for (int i = 0; i <= 23; ++i) {
c[i][0] = 1;
for (int j = 1; j <= i; ++j) {
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
for (int i = 1; i <= m; ++i) {
f[0][i] = -(1LL << 60);
}
for (int i = 1; i <= n; ++i) {
Read(w[i]);
}
for (int i = 1; i <= n; ++i) {
Read(v[i]);
}
for (int i = 1, x, y, w; i < n; ++i) {
Read(x), Read(y), Read(w);
adj[x].pb(mp(y, w)), adj[y].pb(mp(x, w));
}
for (int i = 1; i <= n; ++i) {
b[i] = true;
}
for (int i = 1; i <= n; ++i) {
CheckMax(val_max, Solve(i).X);
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
b[j] = true;
}
Build(i, 0, 0);
pair <LL, LL> ret = Solve(i);
if (ret.X == val_max) {
ans = (ans + C(ret.Y, k)) % mod;
}
}
for (int i = 1; i <= n; ++i) {
for (auto e : adj[i]) {
if (e.X > i) {
for (int j = 1; j <= n; ++j) {
b[j] = true;
}
int j = e.X;
Build(i, 0, 0), Build(j, 0, 0);
if (!b[i] || !b[j]) {
continue;
}
pair <LL, LL> ret = Solve(i, j);
if (ret.X == val_max) {
ans = (ans - C(ret.Y, k) + mod) % mod;
}
}
}
}
printf("%lld\n", ans);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}
完美的旅行:
首先预处理 f(i,j) f ( i , j ) 表示标号的与为 i i ,路径长度为 的方案数,这个相当于求 A1,A2,A3,⋯,Am A 1 , A 2 , A 3 , ⋯ , A m 。
考虑暴力求出特征多项式之后,因为只关心 f(i,j) f ( i , j ) 的答案,可以直接对 f(i,j) f ( i , j ) 而不是整个矩阵进行线性变换,这样就把复杂度降下来了。
计算答案的时候,首先可以FWT求出集合交卷积对应的多项式 F F ,那么就是要求 ,多项式求逆即可。
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;
template <typename T> inline void Read(T &x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template <typename T> inline bool CheckMax(T &a, const T &b) {
return a < b ? a = b, true : false;
}
template <typename T> inline bool CheckMin(T &a, const T &b) {
return a > b ? a = b, true : false;
}
const int N = 65;
const int M = 65540;
const int G = 3;
const int mod = 998244353;
int n, m, D, L, W[N], fac[N], inv[N], val[N], f[M], g[M], R[M], a[N][N], ans[N][M];
struct Matrix {
int a[N][N];
Matrix() {
memset(a, 0, sizeof a);
}
Matrix operator * (const Matrix &b) const {
Matrix c;
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
c.a[i][j] = (1LL * a[i][k] * b.a[k][j] + c.a[i][j]) % mod;
}
}
}
return c;
}
} cur, trs;
inline int Qow(int x, int y) {
int r = 1;
for (; y; y >>= 1, x = 1LL * x * x % mod) {
if (y & 1) {
r = 1LL * r * x % mod;
}
}
return r;
}
inline int Det() {
int ret = 1;
for (int i = 0; i < n; ++i) {
int p = i;
for (; p < n && !a[p][i]; ++p);
if (p == n) {
return 0;
}
if (i != p) {
for (int j = i; j < n; ++j) {
swap(a[p][j], a[i][j]);
}
ret = mod - ret;
}
ret = 1LL * ret * a[i][i] % mod;
for (int j = i + 1; j < n; ++j) {
if (a[j][i]) {
int cof = 1LL * a[j][i] * Qow(a[i][i], mod - 2) % mod;
for (int k = i; k < n; ++k) {
a[j][k] = (a[j][k] - 1LL * a[i][k] * cof % mod + mod) % mod;
}
}
}
}
return ret;
}
inline void Ini(int l) {
for (D = 1, L = 0; D < l; D <<= 1, ++L);
for (int i = 1; i < D; ++i) {
R[i] = (R[i >> 1] >> 1) | ((i & 1) << L - 1);
}
W[0] = Qow(G, mod - 1 >> L);
for (int i = 1; i < L; ++i) {
W[i] = 1LL * W[i - 1] * W[i - 1] % mod;
}
}
inline void IniInv() {
W[0] = Qow(W[0], mod - 2);
for (int i = 1; i < L; ++i) {
W[i] = 1LL * W[i - 1] * W[i - 1] % mod;
}
}
inline void DFT(int *x) {
for (int i = 0; i < D; ++i) {
if (i < R[i]) {
swap(x[i], x[R[i]]);
}
}
for (int i = 1, l = L - 1; i < D; i <<= 1, --l) {
for (int j = 0; j < D; j += i << 1) {
for (int k = 0, w = 1, u, v; k < i; ++k, w = 1LL * w * W[l] % mod) {
u = x[j + k], v = 1LL * x[j + k + i] * w % mod, x[j + k] = (u + v) % mod, x[j + k + i] = (u - v + mod) % mod;
}
}
}
}
inline void Inv(int *a, int n, int *b) {
static int x[M], y[M];
if (n == 1) {
b[0] = Qow(a[0], mod - 2);
} else {
Inv(a, n + 1 >> 1, b), Ini(n << 1);
for (int i = 0; i < D; ++i) {
x[i] = i < n ? a[i] : 0, y[i] = i < n + 1 >> 1 ? b[i] : 0;
}
DFT(x), DFT(y);
for (int i = 0; i < D; ++i) {
x[i] = (2 - 1LL * x[i] * y[i] % mod + mod) * y[i] % mod;
}
IniInv(), DFT(x);
for (int i = 0, v = Qow(D, mod - 2); i < n; ++i) {
b[i] = 1LL * x[i] * v % mod;
}
}
}
int main() {
#ifdef wxh010910
freopen("d.in", "r", stdin);
#endif
Read(n), Read(m), fac[0] = fac[1] = inv[0] = inv[1] = 1;
for (int i = 2; i <= n; ++i) {
fac[i] = 1LL * fac[i - 1] * i % mod;
inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
}
for (int i = 2; i <= n; ++i) {
inv[i] = 1LL * inv[i - 1] * inv[i] % mod;
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
Read(trs.a[i][j]), cur.a[i][j] = i == j;
}
}
for (int i = 1; i <= n + 1; ++i) {
cur = cur * trs;
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
ans[j & k][i] = (ans[j & k][i] + cur.a[j][k]) % mod;
}
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
trs.a[i][j] = (mod - trs.a[i][j]) % mod;
}
}
for (int i = 0; i <= n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
if (j == k) {
a[j][k] = (trs.a[j][k] + i) % mod;
} else {
a[j][k] = trs.a[j][k];
}
}
}
val[i] = Det();
}
for (int i = 1; i <= n; ++i) {
for (int j = n; j >= i; --j) {
val[j] = (val[j] - val[j - 1] + mod) % mod;
}
}
f[0] = val[0], g[0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = i; j; --j) {
g[j] = (g[j - 1] - 1LL * g[j] * (i - 1) % mod + mod) % mod;
}
val[i] = 1LL * val[i] * inv[i] % mod, g[0] = 0;
for (int j = 1; j <= i; ++j) {
f[j] = (1LL * val[i] * g[j] + f[j]) % mod;
}
}
for (int i = 0; i < n; ++i) {
for (int j = n + 2; j <= m; ++j) {
for (int k = 0; k < n; ++k) {
ans[i][j] = (ans[i][j] - 1LL * f[k] * ans[i][j - n + k] % mod + mod) % mod;
}
}
}
for (int t = 1; t <= m; ++t) {
for (int i = 1; i < n; i <<= 1) {
for (int j = 0; j < n; j += i << 1) {
for (int k = 0; k < i; ++k) {
ans[j + k][t] = (ans[j + k][t] + ans[j + k + i][t]) % mod;
}
}
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= m; ++j) {
if (!j) {
f[j] = 1;
} else {
f[j] = (mod - ans[i][j]) % mod;
}
}
Inv(f, m + 1, g);
for (int j = 1; j <= m; ++j) {
ans[i][j] = g[j];
}
}
for (int t = 1; t <= m; ++t) {
for (int i = 1; i < n; i <<= 1) {
for (int j = 0; j < n; j += i << 1) {
for (int k = 0; k < i; ++k) {
ans[j + k][t] = (ans[j + k][t] - ans[j + k + i][t] + mod) % mod;
}
}
}
}
int ret = 0;
for (int i = 0; i < n; ++i) {
for (int j = 1; j <= m; ++j) {
ret ^= ans[i][j];
}
}
printf("%d\n", ret);
#ifdef wxh010910
Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
return 0;
}