Day 1
tree
首先考虑 m=1 怎么做,显然 ∑di=2n−2 ,我们不管它。
记
bi
表示
i
在
ans=(2n−2)(n−2)!∏ni=1ai∑∑ni=1bi=2n−2∏ni=1abii(bi+1)bi! 。
暴力展开 ∏ni=1(bi+1) ,考虑计算一个子序列 bj1,bj2...,bjk的贡献 。
注意到提取出来的
b
可以和分母的
∏kl=1ajl∑∑ni=1bi=n−2−k∏ni=1abiibi!=(∏kl=1ajl)(∑ai)n−k−2(n−k−2)! 。
考虑回到原问题,
(bi+1)m=(bi−1+2)m−1bi+(bi+1)m−1
,第一部分的
bi
类似于
m=1
提到外面跟阶乘消掉,相当于
bi
减去一,提取东西的个数加上一,同时外面系数乘上
ai
,第二部分不变,将这个东西视为一个
m
次多项式,分治
∑dmi 相当于有一个是 2m 次多项式,直接处理掉就好了。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 65540;
const int MAXM = 65;
const int mod = 998244353;
const int G = 3;
int n, m, a[MAXN], fac[MAXN], inv[MAXN], f[MAXM][MAXM];
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;
}
namespace NTT
{
int n, L, W[20], R[MAXN];
inline void Ini(int len)
{
for (n = 1, L = 0; n < len; n <<= 1, L ++);
for (int i = 1; i < n; 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 Ini_Inv()
{
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 FFT(int *x)
{
for (int i = 0; i < n; i ++)
if (i < R[i])
swap(x[i], x[R[i]]);
for (int i = 1, l = L - 1; i < n; i <<= 1, l --)
for (int j = 0; j < n; 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;
}
}
pair <vector <int>, vector <int>> Solve(int l, int r)
{
if (l == r)
{
vector <int> L, R;
int cur = 1;
for (int i = 0; i <= m; i ++)
L.pb(1LL * cur * f[m][i] % mod), R.pb(1LL * cur * f[m << 1][i] % mod), cur = 1LL * cur * a[l] % mod;
for (int i = m + 1; i <= m << 1; i ++)
R.pb(1LL * cur * f[m << 1][i] % mod), cur = 1LL * cur * a[l] % mod;
return mp(L, R);
}
else
{
int mid = l + r >> 1;
pair <vector <int>, vector <int>> L = Solve(l, mid), R = Solve(mid + 1, r);
static int x[MAXN], y[MAXN], z[MAXN], w[MAXN];
NTT::Ini(L.xx.size() + R.yy.size() - 1);
for (int i = 0; i < NTT::n; i ++)
x[i] = i < L.xx.size() ? L.xx[i] : 0, y[i] = i < L.yy.size() ? L.yy[i] : 0, z[i] = i < R.xx.size() ? R.xx[i] : 0, w[i] = i < R.yy.size() ? R.yy[i] : 0;
NTT::FFT(x), NTT::FFT(y), NTT::FFT(z), NTT::FFT(w);
for (int i = 0; i < NTT::n; i ++)
y[i] = (1LL * x[i] * w[i] + 1LL * y[i] * z[i]) % mod, x[i] = 1LL * x[i] * z[i] % mod;
NTT::Ini_Inv(), NTT::FFT(x), NTT::FFT(y);
for (int i = 0, v = Qow(NTT::n, mod - 2); i < NTT::n; i ++)
x[i] = 1LL * x[i] * v % mod, y[i] = 1LL * y[i] * v % mod;
return mp(vector <int> (x, x + min(n - 1, (int)(L.xx.size() + R.xx.size() - 1))), vector <int> (y, y + min(n - 1, (int)(L.xx.size() + R.yy.size() - 1))));
}
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read(), m = Read(), 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 = 1; i <= n; i ++)
a[i] = Read();
if (n == 1)
return puts("0"), 0;
f[0][0] = 1;
for (int i = 1; i <= m << 1; i ++)
for (int j = 0; j <= i; j ++)
f[i][j] = (1LL * f[i - 1][j] * (j + 1) + (j ? f[i - 1][j - 1] : 0)) % mod;
vector <int> ret = Solve(1, n).yy;
int ans = 0, sum = 0, cur = 1;
for (int i = 1; i <= n; i ++)
sum = (sum + a[i]) % mod;
for (int i = n - 2; ~i; i --)
ans = (1LL * cur * ret[i] % mod * inv[n - i - 2] + ans) % mod, cur = 1LL * cur * sum % mod;
for (int i = 1; i <= n; i ++)
ans = 1LL * ans * a[i] % mod;
ans = 1LL * ans * fac[n - 2] % mod;
return printf("%d\n", ans), 0;
}
infinityloop
将网格看成二分图,相当于插头需要匹配。
每个格子再拆四个点,然后上费用流就好了。
建图可以自己推推。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
namespace Flow
{
const int MAXN = 10005;
const int MAXM = 1000005;
const int INF = 0x3f3f3f3f;
struct Edge
{
int p, v, w, c;
} e[MAXM];
int S, T, e_cnt = 1, hed[MAXN], dis[MAXN];
bool vis[MAXN];
inline void Addedge(int x, int y, int w, int c)
{
e[++ e_cnt] = {y, hed[x], w, c}, hed[x] = e_cnt;
e[++ e_cnt] = {x, hed[y], 0, -c}, hed[y] = e_cnt;
}
inline bool SPFA()
{
queue <int> q;
for (int i = 1; i <= T; i ++)
dis[i] = INF, vis[i] = 0;
q.push(S);
while (!q.empty())
{
int x = q.front();
q.pop(), vis[x] = 0;
for (int i = hed[x]; i; i = e[i].v)
if (e[i].w && dis[e[i].p] > dis[x] + e[i].c)
if (dis[e[i].p] = dis[x] + e[i].c, !vis[e[i].p])
vis[e[i].p] = 1, q.push(e[i].p);
}
return dis[T] ^ INF;
}
inline int DFS(int x, int f)
{
vis[x] = 1;
if (x == T)
return f;
int r = 0, d;
for (int i = hed[x]; i; i = e[i].v)
if (!vis[e[i].p] && e[i].w && dis[e[i].p] == dis[x] + e[i].c)
{
d = DFS(e[i].p, min(f - r, e[i].w));
e[i].w -= d, e[i ^ 1].w += d, r += d;
if (r == f)
return r;
}
return r;
}
inline pii Solve()
{
int x = 0, y = 0, z = 0;
while (SPFA())
for (vis[T] = 1; vis[T]; z = DFS(S, INF), x += z, y += z * dis[T])
for (int i = 0; i <= T; i ++)
vis[i] = 0;
return mp(x, y);
}
}
const int MAXN = 2005;
int n, m, cnt, a[MAXN][MAXN], idx[MAXN][MAXN][5];
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
using namespace Flow;
n = Read(), m = Read(), T = n * m * 5 + 1;
int l = 0, r = 0;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
{
a[i][j] = Read();
if (i + j & 1)
l += __builtin_popcount(a[i][j]);
else
r += __builtin_popcount(a[i][j]);
}
if (l ^ r)
return puts("-1"), 0;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
for (int k = 0; k <= 4; k ++)
idx[i][j][k] = ++ cnt;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
if (i + j & 1)
{
Addedge(S, idx[i][j][4], __builtin_popcount(a[i][j]), 0);
if (a[i][j] == 1 || a[i][j] == 2 || a[i][j] == 4 || a[i][j] == 8)
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][4], idx[i][j][k], 1, 0), Addedge(idx[i][j][k], idx[i][j][k ^ 1], 1, 1), Addedge(idx[i][j][k], idx[i][j][k ^ 2], 1, 2), Addedge(idx[i][j][k], idx[i][j][k ^ 3], 1, 1);
}
else if (a[i][j] == 3 || a[i][j] == 6 || a[i][j] == 12 || a[i][j] == 9)
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][4], idx[i][j][k], 1, 0), Addedge(idx[i][j][k], idx[i][j][k ^ 2], 1, 1);
}
else if (a[i][j] == 5 || a[i][j] == 10 || a[i][j] == 15)
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][4], idx[i][j][k], 1, 0);
}
else
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][4], idx[i][j][k], 1, 0);
else
Addedge(idx[i][j][k ^ 1], idx[i][j][k], 1, 1), Addedge(idx[i][j][k ^ 2], idx[i][j][k], 1, 2), Addedge(idx[i][j][k ^ 3], idx[i][j][k], 1, 1);
}
}
else
{
Addedge(idx[i][j][4], T, __builtin_popcount(a[i][j]), 0);
if (a[i][j] == 1 || a[i][j] == 2 || a[i][j] == 4 || a[i][j] == 8)
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][k], idx[i][j][4], 1, 0), Addedge(idx[i][j][k ^ 1], idx[i][j][k], 1, 1), Addedge(idx[i][j][k ^ 2], idx[i][j][k], 1, 2), Addedge(idx[i][j][k ^ 3], idx[i][j][k], 1, 1);
}
else if (a[i][j] == 3 || a[i][j] == 6 || a[i][j] == 12 || a[i][j] == 9)
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][k], idx[i][j][4], 1, 0), Addedge(idx[i][j][k ^ 2], idx[i][j][k], 1, 1);
}
else if (a[i][j] == 5 || a[i][j] == 10 || a[i][j] == 15)
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][k], idx[i][j][4], 1, 0);
}
else
{
for (int k = 0; k < 4; k ++)
if (a[i][j] >> k & 1)
Addedge(idx[i][j][k], idx[i][j][4], 1, 0);
else
Addedge(idx[i][j][k], idx[i][j][k ^ 1], 1, 1), Addedge(idx[i][j][k], idx[i][j][k ^ 2], 1, 2), Addedge(idx[i][j][k], idx[i][j][k ^ 3], 1, 1);
}
}
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
if (i + j & 1)
{
if (i)
Addedge(idx[i][j][0], idx[i - 1][j][2], 1, 0);
if (j < m)
Addedge(idx[i][j][1], idx[i][j + 1][3], 1, 0);
if (i < n)
Addedge(idx[i][j][2], idx[i + 1][j][0], 1, 0);
if (j)
Addedge(idx[i][j][3], idx[i][j - 1][1], 1, 0);
}
pii ret = Solve();
if (ret.xx ^ l)
return puts("-1"), 0;
return printf("%d\n", ret.yy), 0;
}
helloworld
根号分治,大于根号的暴力跳,小于根号的用数据结构维护根号棵树, 第
i
棵树的父亲实际上是
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline LL Read()
{
LL x = 0; int f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 50005;
const int MAXM = 240;
const int M = 233;
const int B = 20;
int n, m, tim, dep[MAXN], par[MAXN], g[16][MAXN], f[MAXM][MAXN], dfn[MAXM][MAXN], siz[MAXM][MAXN], anc_big[MAXM][MAXN], anc_small[MAXM][MAXN];
vector <int> dfs_seq, adj[MAXN], adv[MAXM][MAXN];
LL a[MAXN], bit[MAXM][MAXN];
inline void DFS(int x)
{
dfs_seq.pb(x), anc_small[0][x] = anc_big[0][x] = x, g[0][x] = par[x];
for (int i = 1; i <= M; i ++)
anc_small[i][x] = par[anc_small[i - 1][x]];
for (int i = 1; i <= M; i ++)
anc_big[i][x] = anc_small[M][anc_big[i - 1][x]];
for (int i = 1; i <= 15; i ++)
g[i][x] = g[i - 1][g[i - 1][x]];
for (auto y : adj[x])
if (y ^ par[x])
par[y] = x, dep[y] = dep[x] + 1, DFS(y);
}
inline int Anc(int x, int k)
{
return anc_big[k / M][anc_small[k % M][x]];
}
inline int LCA(int x, int y)
{
if (dep[x] > dep[y])
x = Anc(x, dep[x] - dep[y]);
else if (dep[x] < dep[y])
y = Anc(y, dep[y] - dep[x]);
if (x == y)
return x;
for (int i = 15; ~i; i --)
if (g[i][x] ^ g[i][y])
x = g[i][x], y = g[i][y];
return g[0][x];
}
inline void DFS(int x, int b)
{
dfn[b][x] = ++ tim, siz[b][x] = 1;
for (auto y : adv[b][x])
DFS(y, b), siz[b][x] += siz[b][y];
}
inline int Fnd(int x, int b)
{
while (x ^ f[b][x])
x = f[b][x] = f[b][f[b][x]];
return x;
}
inline void Modify(int x, int b, LL v)
{
for (; x <= n; x += x & -x)
bit[b][x] += v;
}
inline LL Query(int x, int b)
{
LL r = 0;
for (; x; x -= x & -x)
r += bit[b][x];
return r;
}
inline void Modify(int x, LL v)
{
for (int i = 1; i <= B; i ++)
Modify(dfn[i][x], i, v), Modify(dfn[i][x] + siz[i][x], i, -v);
}
inline void Modify(int x)
{
if (a[x] == 1)
return ;
Modify(x, (LL)sqrt(a[x]) - a[x]), a[x] = sqrt(a[x]);
if (a[x] == 1)
for (int i = 1; i <= B; i ++)
f[i][x] = Fnd(anc_small[i][x], i);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read();
for (int i = 1; i <= n; i ++)
a[i] = Read();
for (int i = 1, x, y; i < n; i ++)
x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
dep[1] = 1, DFS(1);
for (int j = 1; j <= B; j ++)
for (int i = 1; i <= n; i ++)
if (anc_small[j][i])
adv[j][anc_small[j][i]].pb(i);
for (int j = 1; j <= B; tim = 0, j ++)
for (int i = 0; i < n; i ++)
if (!dfn[j][dfs_seq[i]])
DFS(dfs_seq[i], j);
for (int j = 1; j <= B; j ++)
for (int i = 1; i <= n; i ++)
f[j][i] = i;
for (int i = 1; i <= n; i ++)
Modify(i, a[i]);
for (int i = 1; i <= n; i ++)
if (a[i] == 1)
for (int j = 1; j <= B; j ++)
f[j][Fnd(i, j)] = Fnd(anc_small[j][i], j);
m = Read();
while (m --)
{
int opt = Read(), s = Read(), t = Read(), k = Read(), p = LCA(s, t), len = dep[s] + dep[t] - (dep[p] << 1);
if (k > B)
{
if (opt)
{
int x = s, y = s;
LL ret = 0;
for (; dep[x] >= dep[p]; y = x, x = Anc(x, k))
ret += a[x];
if (y ^ t)
for (ret += a[t], x = Anc(t, (len - 1) % k + 1); dep[x] > dep[p]; x = Anc(x, k))
ret += a[x];
printf("%lld\n", ret);
}
else
{
int x = s, y = s;
for (; dep[x] >= dep[p]; y = x, x = Anc(x, k))
Modify(x);
if (y ^ t)
for (Modify(t), x = Anc(t, (len - 1) % k + 1); dep[x] > dep[p]; x = Anc(x, k))
Modify(x);
}
}
else
{
if (opt)
{
LL ret = 0;
int x = s, y = par[p];
if (dep[x] % k > dep[y] % k)
y = anc_small[k - dep[x] % k + dep[y] % k][y];
else
y = anc_small[dep[y] % k - dep[x] % k][y];
ret = Query(dfn[k][x], k) - Query(dfn[k][y], k);
if (((dep[x] - dep[p]) % k) || (t ^ p))
{
ret += a[t], t = Anc(t, (len - 1) % k + 1);
x = t, y = p;
if (dep[x] % k > dep[y] % k)
y = anc_small[k - dep[x] % k + dep[y] % k][y];
else
y = anc_small[dep[y] % k - dep[x] % k][y];
ret += Query(dfn[k][x], k) - Query(dfn[k][y], k);
}
printf("%lld\n", ret);
}
else
{
int x = s;
for (x = Fnd(x, k); dep[x] >= dep[p]; x = Fnd(anc_small[k][x], k))
Modify(x);
if (((dep[s] - dep[p]) % k) || (t ^ p))
for (Modify(t), x = Fnd(Anc(t, (len - 1) % k + 1), k); dep[x] > dep[p]; x = Fnd(anc_small[k][x], k))
Modify(x);
}
}
}
return 0;
}
Day 2
metro
首先每个点可以向上向下,这样我们可以得到一个 O(2n×poly(n)) 的算法。
将点按照左端点排序,不难发现这个位置对之后的影响只跟右端点的决策有关,所以变成了 O(2n/2×poly(n)) 。
加上最优性剪枝即可。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
int n, m, ans, a[50], l[25], r[25], p[25], q[25];
inline int F(int x, int u, int v)
{
int ret = 0;
for (int i = 0; i < x; i ++)
if (l[x] < r[i])
if (r[x] < r[i])
ret += u ^ v;
else if (p[i] == q[i])
ret += u == p[i];
else
ret += u == q[i];
return ret;
}
inline void DFS(int x, int cur)
{
if (cur >= ans)
return ;
if (x == m)
return (void)(ans = cur);
int u, v;
u = F(x, 0, 0), v = F(x, 1, 0);
if (u < v)
p[x] = 0, q[x] = 0, DFS(x + 1, cur + u);
else
p[x] = 1, q[x] = 0, DFS(x + 1, cur + v);
u = F(x, 0, 1), v = F(x, 1, 1);
if (u < v)
p[x] = 0, q[x] = 1, DFS(x + 1, cur + u);
else
p[x] = 1, q[x] = 1, DFS(x + 1, cur + v);
}
inline void Solve()
{
n = Read(), m = 0, ans = 1 << 30;
for (int i = 1; i <= n; i ++)
a[i] = Read();
for (int i = 1; i <= n; i ++)
for (int j = i + 1; j <= n; j ++)
if (a[i] == a[j])
l[m] = i, r[m] = j, m ++;
DFS(0, 0);
printf("%d\n", ans);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
for (int T = Read(); T; T --)
Solve();
return 0;
}
binary
预处理子树内和子树外的最小字典序遍历,然后贪心。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
const int MAXN = 1000005;
char B[1 << 23], *S = B, *T = B, C[1 << 23], *A = C;
inline char GetChar()
{
if (S == T)
T = (S = B) + fread(B, 1, 1 << 23, stdin);
return S == T ? 0 : *S ++;
}
inline int Read()
{
int x = 0, f = 1, c = GetChar();
for (; !isdigit(c); c = GetChar())
if (c == '-')
f = -1;
for (; isdigit(c); c = GetChar())
x = x * 10 + c - '0';
return x * f;
}
inline int Write(int x)
{
static int c[20], t;
if (!x)
*A ++ = '0';
else
{
if (x < 0)
*A ++ = '-', x = -x;
for (t = 0; x; c[t ++] = x % 10 + '0', x /= 10);
for (; t --; *A ++ = c[t]);
}
}
int n, m, k[MAXN], f[MAXN], g[MAXN], ans[MAXN], par[MAXN], chd[MAXN][2], a[MAXN][4];
bool vis[MAXN];
inline void DFS_F(int x)
{
for (int i = 1; i <= k[x]; i ++)
if (a[x][i] ^ par[x])
{
par[a[x][i]] = x, DFS_F(a[x][i]);
if (!chd[x][0])
chd[x][0] = a[x][i];
else
chd[x][1] = a[x][i];
}
if (!chd[x][0])
f[x] = x;
else if (chd[x][1])
f[x] = min(f[chd[x][0]], f[chd[x][1]]);
else
f[x] = min(f[chd[x][0]], x);
}
inline void DFS_G(int x)
{
if (chd[x][1])
g[chd[x][0]] = min(g[x], f[chd[x][1]]), g[chd[x][1]] = min(g[x], f[chd[x][0]]), DFS_G(chd[x][0]), DFS_G(chd[x][1]);
else if (chd[x][0])
g[chd[x][0]] = min(x, g[x]), DFS_G(chd[x][0]);
}
inline void Solve(int x, bool t)
{
vis[x] = true;
if (t)
{
if (!chd[x][0])
ans[++ m] = x;
else if (chd[x][1])
{
if (f[chd[x][0]] < f[chd[x][1]])
Solve(chd[x][0], 1), ans[++ m] = x, Solve(chd[x][1], 1);
else
Solve(chd[x][1], 1), ans[++ m] = x, Solve(chd[x][0], 1);
}
else
{
if (x < f[chd[x][0]])
ans[++ m] = x, Solve(chd[x][0], 1);
else
Solve(chd[x][0], 1), ans[++ m] = x;
}
}
else
{
ans[++ m] = x;
int p[4], v[4], c = 0;
for (int i = 1; i <= k[x]; i ++)
if (!vis[a[x][i]])
p[++ c] = a[x][i], v[c] = a[x][i] == par[x] ? g[x] : f[a[x][i]];
if (!c)
return ;
else if (c == 1)
Solve(p[1], v[1] <= p[1]);
else if (v[1] < v[2])
Solve(p[1], 1), Solve(p[2], 0);
else
Solve(p[2], 1), Solve(p[1], 0);
}
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read();
for (int i = 1, j; i <= n; i ++)
for (j = 1, k[i] = Read(); j <= k[i]; j ++)
a[i][j] = Read();
int p = 0;
for (int i = n; i; i --)
if (k[i] <= 2)
p = i;
DFS_F(p), g[p] = n + 1, DFS_G(p), Solve(p, 0);
for (int i = 1; i <= n; i ++)
Write(ans[i]), *A ++ = i == n ? '\n' : ' ';
fwrite(C, 1, A - C, stdout);
return 0;
}
patron
首先状态只有 (m+kk) 种,矩乘即可。
预处理 2 的次幂的矩阵,每次询问用向量乘矩阵。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline LL Read()
{
LL x = 0; int f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 170;
const int mod = 998244353;
int T, m, k, tot, cur[4], ret[MAXN], tmp[MAXN], a[MAXN][4];
map <int, int> idx;
struct Matrix
{
int a[MAXN][MAXN];
Matrix() { mset(a, 0); }
Matrix operator * (const Matrix &b) const
{
Matrix c;
for (int k = 0; k <= tot; k ++)
for (int i = 0; i <= tot; i ++)
for (int j = 0; j <= tot; j ++)
c.a[i][k] = (1LL * a[i][j] * b.a[j][k] + c.a[i][k]) % mod;
return c;
}
} mat[60];
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 void DFS(int x, int y)
{
if (!x)
{
int val = 0;
cur[x] = y, tot ++;
for (int i = 0; i <= m; i ++)
a[tot][i] = cur[i], val = val * 9 + cur[i];
idx[val] = tot;
return ;
}
for (cur[x] = 0; cur[x] <= y; cur[x] ++)
DFS(x - 1, y - cur[x]);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
T = Read(), m = Read(), k = Read();
DFS(m, k), mat[0].a[0][0] = 1;
for (int i = 1; i <= tot; i ++)
{
int sum = Qow(k - a[i][0] + 1, mod - 2);
mat[0].a[i][i] = mat[0].a[i][0] = sum;
for (int j = 1; j <= m; j ++)
if (a[i][j])
{
mcpy(cur, a[i]);
cur[j] --, cur[j - 1] ++;
if ((j ^ 1) && (cur[0]))
cur[0] --, cur[m] ++;
int val = 0;
for (int j = 0; j <= m; j ++)
val = val * 9 + cur[j];
val = idx[val];
mat[0].a[i][val] = (1LL * a[i][j] * sum + mat[0].a[i][val]) % mod;
}
}
for (int i = 1; i < 60; i ++)
mat[i] = mat[i - 1] * mat[i - 1];
while (T --)
{
LL n = Read();
for (int i = 0; i <= tot; i ++)
ret[i] = 0;
int val = 0;
cur[0] = k - 1;
for (int i = 1; i <= m; i ++)
cur[i] = i == m;
for (int i = 0; i <= m; i ++)
val = val * 9 + cur[i];
ret[idx[val]] = 1;
for (int k = 59; ~k; k --)
if (n >> k & 1)
{
for (int i = 0; i <= tot; i ++)
tmp[i] = 0;
for (int i = 0; i <= tot; i ++)
for (int j = 0; j <= tot; j ++)
tmp[j] = (1LL * ret[i] * mat[k].a[i][j] + tmp[j]) % mod;
for (int i = 0; i <= tot; i ++)
ret[i] = tmp[i];
}
printf("%d\n", ret[0]);
}
}
Day 3
dsa
每次操作暴力维护
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 1000005;
const int MAXM = 25;
int n, m, q, l, r, ans[MAXM], a[MAXN], f[MAXN], plc[MAXN], g[MAXN][MAXM];
vector <int> fac[MAXN];
inline int Get(int x)
{
for (int i = 20; i; i --)
if (g[x][i])
return i + 1;
return 1;
}
inline void Add(int x, int v)
{
for (auto i : fac[x])
if (plc[i] && plc[i] < plc[x])
g[i][f[x]] += v;
ans[f[x]] += v;
}
inline void AddL(int x)
{
l --, a[l] = x, plc[x] = l, f[x] = 0, mset(g[x], 0);
for (int i = x; i <= m; i += x)
if (plc[i])
g[x][f[i]] ++;
f[x] = Get(x), ans[f[x]] ++;
}
inline void AddR(int x)
{
r ++, a[r] = x, plc[x] = r, f[x] = 1, Add(x, 1), mset(g[x], 0);
for (auto i : fac[x])
if (plc[i])
{
int d = Get(i);
if (d ^ f[i])
Add(i, -1), f[i] = d, Add(i, 1);
}
}
inline void DelL()
{
int x = a[l ++];
plc[x] = 0, ans[f[x]] --, f[x] = 0;
}
inline void DelR()
{
int x = a[r --];
Add(x, -1), plc[x] = 0, f[x] = 0;
for (auto i : fac[x])
if (plc[i])
{
int d = Get(i);
if (d ^ f[i])
Add(i, -1), f[i] = d, Add(i, 1);
}
}
inline void Print()
{
for (int i = 20; i; i --)
if (ans[i])
return (void)printf("%d %d\n", i, ans[i]);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
n = Read(), m = Read(), q = Read();
for (int i = m; i; i --)
for (int j = i; j <= m; j += i)
fac[j].pb(i);
l = q + 1, r = q;
for (int i = 1; i <= n; i ++)
AddR(Read());
Print();
while (q --)
{
int opt = Read();
if (!opt)
AddL(Read());
else if (opt == 1)
AddR(Read());
else if (opt == 2)
DelL();
else
DelR();
Print();
}
return 0;
}
frogs
把转移写出来,然后可以手推,下面几层是
一些特殊情况是 ⋆={0|0},↑={0|⋆},↓={⋆|0} ,具体可以参见题解。
计数部分就是组合数前缀和。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 1000005;
const int mod = 998244353;
int sum[MAXN], fac[MAXN], inv[MAXN], bin[MAXN];
inline int C(int x, int y)
{
if (x < 0 || y < 0 || x < y)
return 0;
return 1LL * fac[x] * inv[y] % mod * inv[x - y] % mod;
}
inline void Solve()
{
int n = Read(), u = 0, d = 0, s = 0, x = 0, y = 0, z = 0, v = 0, w = 0;
for (int i = 1; i <= n; i ++)
{
string str;
cin >> str;
if (str == "LL_RR" || str == "LRL_R" || str == "L_RLR")
s += Read();
else if (str == "L_LRR")
u += Read();
else if (str == "LLR_R")
d += Read();
else if (str == "RL_LR")
v += Read();
else if (str == "LR_RL")
w += Read();
else if (str == "LRRL_" || str == "RRL_L" || str == "RLRL_")
y += Read();
else if (str == "_RLLR" || str == "R_RLL" || str == "_RLRL")
z += Read();
else
x += Read();
}
int ansl = 0, ansr = 0, ansf = 0, anss = 0, zero = 0, a = v + w, b = y + z, k = (z << 1) + w, ways = 0;
for (int i = 0; i <= a; i ++)
sum[i] = C(a, i);
for (int i = a - 1; ~i; i --)
sum[i] = (sum[i] + sum[i + 1]) % mod;
for (int i = 0; i <= b; i ++)
{
int ways = C(b, i), cur = k + 1 - (i << 1);
if (cur > a)
continue;
else if (cur < 0)
cur = 0;
ansl = (1LL * ways * sum[cur] + ansl) % mod;
}
for (int i = 0; i <= a; i ++)
sum[i] = C(a, i);
for (int i = 1; i <= a; i ++)
sum[i] = (sum[i] + sum[i - 1]) % mod;
for (int i = 0; i <= b; i ++)
{
int ways = C(b, i), cur = k - 1 - (i << 1);
if (cur < 0)
break;
else if (cur > a)
cur = a;
ansr = (1LL * ways * sum[cur] + ansr) % mod;
}
zero = (0LL + bin[a + b] - ansl - ansr + mod + mod) % mod * bin[x] % mod;
ansl = 1LL * ansl * bin[x + u + d + s] % mod;
ansr = 1LL * ansr * bin[x + u + d + s] % mod;
ways = 0;
for (int i = 0; i <= s; i += 2)
ways = (ways + C(s, i)) % mod;
ways = 1LL * ways * zero % mod;
for (int i = 0; i <= d; i ++)
sum[i] = C(d, i);
for (int i = 1; i <= d; i ++)
sum[i] = (sum[i] + sum[i - 1]) % mod;
for (int i = 1; i <= u; i ++)
ansl = (1LL * C(u, i) * sum[min(i - 1, d)] % mod * ways + ansl) % mod;
for (int i = 0; i <= d; i ++)
sum[i] = C(d, i);
for (int i = d - 1; ~i; i --)
sum[i] = (sum[i] + sum[i + 1]) % mod;
for (int i = 0; i <= u && i < d; i ++)
ansr = (1LL * C(u, i) * sum[i + 1] % mod * ways + ansr) % mod;
for (int i = 0; i <= min(u, d); i ++)
anss = (1LL * C(u, i) * C(d, i) % mod * ways + anss) % mod;
ways = 0;
for (int i = 1; i <= s; i += 2)
ways = (ways + C(s, i)) % mod;
ways = 1LL * ways * zero % mod;
for (int i = 0; i <= d; i ++)
sum[i] = C(d, i);
for (int i = 1; i <= d; i ++)
sum[i] = (sum[i] + sum[i - 1]) % mod;
for (int i = 2; i <= u; i ++)
ansl = (1LL * C(u, i) * sum[min(i - 2, d)] % mod * ways + ansl) % mod;
for (int i = 0; i <= d; i ++)
sum[i] = C(d, i);
for (int i = d - 1; ~i; i --)
sum[i] = (sum[i] + sum[i + 1]) % mod;
for (int i = 0; i <= u && i + 1 < d; i ++)
ansr = (1LL * C(u, i) * sum[i + 2] % mod * ways + ansr) % mod;
for (int i = 0; i <= u; i ++)
ansf = (1LL * C(u, i) * (0LL + C(d, i - 1) + C(d, i) + C(d, i + 1)) % mod * ways + ansf) % mod;
printf("%d %d %d %d\n", ansl, ansr, ansf, anss);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
Read(), fac[0] = fac[1] = inv[0] = inv[1] = bin[0] = 1;
int N = 1000000;
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 = 1; i <= N; i ++)
inv[i] = 1LL * inv[i - 1] * inv[i] % mod, bin[i] = (bin[i - 1] << 1) % mod;
for (int T = Read(); T; T --)
Solve();
return 0;
}
hafen
打表发现存在反例可以表示成 i,j,j 的形式,对于小范围可以直接暴力。
对于大范围的数据,还可以发现可以表示成
x=p×q
的形式,然后
p
大约是
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
inline bool IsPrime(int x)
{
if (x < 2)
return false;
for (int i = 2; i * i <= x; i ++)
if (x % i == 0)
return false;
return true;
}
inline void Solve()
{
int n = Read();
if (n <= 200)
{
for (int i = 2; i < n; i ++)
for (int j = i; j < n; j ++)
{
LL x = i * j * j;
int cnt = 0;
for (int k = n - 1; k > 1; k --)
while (x % k == 0)
x /= k, cnt ++;
if (cnt > 3)
{
printf("3 %d %d %d\n", i, j, j);
goto OK;
}
}
puts("-1");
OK:;
}
else
{
int x = ceil(sqrt(n)), y = pow(n - 1, 1.0 / 3);
for (; !IsPrime(x); x ++);
for (; !IsPrime(y); y --);
printf("3 %d %d %d\n", x * y, x * y, x * y);
}
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
for (int T = Read(); T; T --)
Solve();
return 0;
}
Day 4
game
每次暴力找循环节,那么每次线的长度相当于对循环节取模,所以至少除以二。
预处理极角排序,每次暴力往下找,因为转了一圈所以均摊下来是线性的。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 1005;
const double PI = acos(-1);
const double eps = 1e-8;
int n, m, tim, vis[MAXN][MAXN];
double dis[MAXN][MAXN];
inline int Sgn(double x) { return fabs(x) < eps ? 0 : x > 0 ? 1 : -1; }
inline int Cmp(double x, double y) { return Sgn(x - y); }
struct Point
{
double x, y;
Point(double x = 0, double y = 0):x(x), y(y) {}
Point operator + (const Point &b) const { return Point(x + b.x, y + b.y); }
Point operator - (const Point &b) const { return Point(x - b.x, y - b.y); }
Point operator * (const double &b) const { return Point(x * b, y * b); }
Point operator / (const double &b) const { return Point(x / b, y / b); }
double operator * (const Point &b) const { return x * b.y - y * b.x; }
inline double Len() { return sqrt(x * x + y * y); }
inline double Ang() { return atan2(y, x); }
inline Point Nor() { return (*this) / Len(); }
inline bool Bel() { return Sgn(y) > 0 || (!Sgn(y) && Sgn(x) < 0); }
} p[MAXN], tmp[MAXN];
struct Node
{
int cnt, a[MAXN], per[MAXN], pos[MAXN];
double all, d[MAXN], val[MAXN];
inline void Init(int x)
{
int m = 0, lst = 0;
for (int i = 1; i <= n; i ++)
if (i ^ x)
tmp[i] = p[i] - p[x], tmp[i + n] = p[x] - p[i], d[i] = d[i + n] = dis[i][x], per[++ m] = i, per[++ m] = i + n;
sort(per + 1, per + m + 1, [&](const int &x, const int &y)
{
if (tmp[x].Bel() ^ tmp[y].Bel())
return tmp[x].Bel() > tmp[y].Bel();
double crs = tmp[x] * tmp[y];
return Sgn(crs) ? Sgn(crs) < 0 : d[x] > d[y];
});
cnt = 0, all = 1e9;
for (int i = 1; i <= m; i ++)
if (per[i] <= n)
{
a[++ cnt] = per[i], all = min(all, val[cnt] = d[per[i]]);
for (int j = lst + 1; j < i; j ++)
pos[per[j] - n] = cnt;
lst = i;
}
for (int i = lst + 1; i <= m; i ++)
pos[per[i] - n] = 1;
}
inline int FindNext(int x, double len)
{
if (Cmp(all, len) > 0)
return 0;
for (x = pos[x]; Cmp(val[x], len) > 0; x = x % cnt + 1);
return a[x];
}
} a[MAXN];
inline double Dis(Point x, Point y)
{
return (x - y).Len();
}
inline double Turn(Point x, Point y, Point z)
{
double ang = (y - x).Ang() - (z - x).Ang();
if (Sgn(ang) < 0)
ang += PI * 2;
else if (Cmp(ang, PI * 2) > 0)
ang -= PI * 2;
return ang;
}
inline int FindNext(Point s, Point t, int ban)
{
double ang = 1e9, dis = 1e9, len = Dis(s, t), cur_ang, cur_dis;
int pos = 0;
for (int i = 1; i <= n; i ++)
if ((i ^ ban) && Cmp(len, cur_dis = Dis(s, p[i])) >= 0 && (Cmp(cur_ang = Turn(s, t, p[i]), ang) < 0 || (!Cmp(cur_ang, ang) && cur_dis > dis)))
pos = i, ang = cur_ang, dis = cur_dis;
return pos;
}
inline int Work()
{
int pre, cur, nxt, ret = 2;
Point s, t;
double len;
s.x = Read(), s.y = Read(), t.x = Read(), t.y = Read(), len = Read(), t = s + (t - s).Nor() * len;
if (!(cur = FindNext(s, t, 0)))
return 1;
len -= Dis(s, p[cur]), t = p[cur] + (p[cur] - s).Nor() * len, s = p[pre = cur];
if (!(cur = FindNext(s, t, pre)))
return 2;
len -= Dis(s, p[cur]);
while (true)
{
int m = 1, pos = 1, cnt = 0, times;
double pre_len = len, cir = 0;
vector <int> vec;
vec.pb(pre), vec.pb(cur), tim ++;
while (true)
{
vec.pb(nxt = a[cur].FindNext(pre, len)), m ++;
if (!nxt)
return ret + vec.size() - 2;
len -= dis[cur][nxt];
if (vis[pre][cur] == tim)
break;
vis[pre][cur] = tim, pre = cur, cur = nxt;
}
for (len = pre_len; (vec[pos - 1] ^ pre) || (vec[pos] ^ cur); pos ++)
ret ++, len -= dis[vec[pos]][vec[pos + 1]];
for (; pos < m - 1; pos ++)
cnt ++, cir += dis[vec[pos]][vec[pos + 1]];
times = len / cir, ret += times * cnt, len -= times * cir, pre = vec[m - 2], cur = vec[m - 1];
}
}
inline void Solve()
{
n = Read(), m = Read();
for (int i = 1; i <= n; i ++)
p[i].x = Read(), p[i].y = Read();
for (int i = 1; i <= n; i ++)
for (int j = i; j <= n; j ++)
dis[i][j] = dis[j][i] = Dis(p[i], p[j]);
for (int i = 1; i <= n; i ++)
a[i].Init(i);
for (int i = 1; i <= m; i ++)
printf("%d\n", Work());
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
for (int T = Read(); T; T --)
Solve();
return 0;
}
core
首先判断深度的奇偶性。
注意到子树内的点可以相互抵消,而如果某个子树过大,那么可以先进去再出来,让那个子树内的点互相抵消。
做一遍树形 DP 就好了。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 100005;
int n, sub, f[MAXN], par[MAXN], dep[MAXN], siz[MAXN], ans[MAXN];
pii pre[MAXN], suf[MAXN];
vector <int> adj[MAXN];
inline void DFS(int x)
{
siz[x] = 1;
if (x ^ 1)
adj[x].erase(find(adj[x].begin(), adj[x].end(), par[x]));
for (auto y : adj[x])
par[y] = x, dep[y] = dep[x] + 1, DFS(y), siz[x] += siz[y];
}
inline void DP(int x)
{
pii cur = mp(0, 0);
int tot = 0;
for (auto y : adj[x])
DP(y), cur = max(cur, mp(siz[y], y)), tot += siz[y];
f[x] = min(max(cur.xx - (tot - cur.xx), 0), max(f[cur.yy] + cur.xx + 1 - tot, 0));
}
inline void DFS(int x, int tot, pii cur)
{
int val = cur.xx, pos = cur.yy;
for (int i = 0; i < adj[x].size(); i ++)
tot += siz[adj[x][i]];
for (int i = 0; i < adj[x].size(); i ++)
pre[adj[x][i]] = max(i ? pre[adj[x][i - 1]] : cur, mp(siz[adj[x][i]], adj[x][i]));
for (int i = adj[x].size() - 1; ~i; i --)
suf[adj[x][i]] = max(i + 1 < adj[x].size() ? suf[adj[x][i + 1]] : cur, mp(siz[adj[x][i]], adj[x][i]));
if (!adj[x].empty())
val = suf[adj[x][0]].xx, pos = suf[adj[x][0]].yy;
if (((dep[x] ^ n) & 1) && (val <= tot - val || f[pos] <= tot - val - 1))
ans[x] = 1;
else
ans[x] = 0;
for (int i = 0; i < adj[x].size(); i ++)
DFS(adj[x][i], tot - siz[adj[x][i]], max(i ? pre[adj[x][i - 1]] : cur, i + 1 < adj[x].size() ? suf[adj[x][i + 1]] : cur));
}
inline void Solve()
{
n = Read();
for (int i = 1; i <= n; i ++)
adj[i].clear();
for (int i = 1, x, y; i < n; i ++)
x = Read(), y = Read(), adj[x].pb(y), adj[y].pb(x);
DFS(1), DP(1), DFS(1, 0, mp(0, 0));
if (sub == 3)
putchar(ans[1] + '0');
else
for (int i = 1; i <= n; i ++)
putchar(ans[i] + '0');
putchar(10);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
sub = Read();
for (int T = Read(); T; T --)
Solve();
return 0;
}
rmq
首先离散化,接下来就知道每个部分的最大值了。
特判掉不合法的情况,接下来从小到大处理,可以转化为:有若干个区间,区间内至少有一个最大值,问方案数。
fi 表示最后一个最大值在 i <script type="math/tex" id="MathJax-Element-44">i</script>这段区间的方案数,暴力转移。
#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define mset(x, y) memset(x, y, sizeof x)
#define mcpy(x, y) memcpy(x, y, sizeof x)
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
inline int Read()
{
int x = 0, f = 1, c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
f = -1;
for (; isdigit(c); c = getchar())
x = x * 10 + c - '0';
return x * f;
}
const int MAXN = 1005;
const int mod = 998244353;
struct Node
{
int l, r, a;
bool operator < (const Node &b) const
{
return a < b.a;
}
} a[MAXN];
int n, m, c, top, ret, val[MAXN], l[MAXN], f[MAXN];
bool vis[MAXN];
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 void Solve(int L, int R)
{
vector <int> seq, sum;
for (int i = L; i <= R; i ++)
for (int j = a[i].l; j < a[i].r; j ++)
if (!vis[j])
vis[j] = 1, seq.pb(j);
sort(seq.begin(), seq.end());
int n = seq.size();
for (int i = 0; i < n; i ++)
sum.pb(l[seq[i] + 1] - l[seq[i]] + (i ? sum[i - 1] : 0));
for (int i = L; i <= R; i ++)
a[i].l = lower_bound(seq.begin(), seq.end(), a[i].l) - seq.begin(), a[i].r = lower_bound(seq.begin(), seq.end(), a[i].r) - seq.begin() - 1;
f[0] = 1;
for (int i = 0; i < n; i ++)
{
int ways = (Qow(a[L].a, l[seq[i] + 1] - l[seq[i]]) - Qow(a[L].a - 1, l[seq[i] + 1] - l[seq[i]]) + mod) % mod, p = 0;
f[i + 1] = 0;
for (int j = L; j <= R; j ++)
if (a[j].r < i)
p = max(p, a[j].l + 1);
for (int j = p; j <= i; j ++)
f[i + 1] = (1LL * f[j] * Qow(a[L].a - 1, (i ? sum[i - 1] : 0) - (j ? sum[j - 1] : 0)) + f[i + 1]) % mod;
f[i + 1] = 1LL * f[i + 1] * ways % mod;
}
int ans = 0, p = 0;
for (int i = L; i <= R; i ++)
p = max(p, a[i].l + 1);
for (int i = p; i <= n; i ++)
ans = (1LL * f[i] * Qow(a[L].a - 1, sum[n - 1] - sum[i - 1]) + ans) % mod;
ret = 1LL * ret * ans % mod;
}
inline void Solve()
{
n = Read(), m = Read(), c = Read(), top = 0, ret = 1;
l[++ top] = 1, l[++ top] = n + 1;
for (int i = 1; i <= m; i ++)
l[++ top] = a[i].l = Read(), l[++ top] = a[i].r = Read() + 1, a[i].a = Read();
sort(l + 1, l + top + 1), top = unique(l + 1, l + top + 1) - l - 1, sort(a + 1, a + m + 1);
for (int i = 1; i < top; i ++)
vis[i] = 0, val[i] = -1;
for (int i = m; i; i --)
{
a[i].l = lower_bound(l + 1, l + top + 1, a[i].l) - l, a[i].r = lower_bound(l + 1, l + top + 1, a[i].r) - l;
for (int j = a[i].l; j < a[i].r; j ++)
val[j] = a[i].a;
}
for (int i = 1; i <= m; i ++)
{
int v = 0;
for (int j = a[i].l; j < a[i].r; j ++)
v = max(v, val[j]);
if (v ^ a[i].a)
return (void)puts("0");
}
for (int i = 1, j = 1; i <= m; i = j)
{
while (j <= m && a[j].a == a[i].a)
j ++;
Solve(i, j - 1);
}
int cnt = 0;
for (int i = 1; i < top; i ++)
if (!vis[i])
cnt += l[i + 1] - l[i];
ret = 1LL * ret * Qow(c, cnt) % mod;
printf("%d\n", ret);
}
int main()
{
#ifdef wxh010910
freopen("data.in", "r", stdin);
#endif
for (int T = Read(); T; T --)
Solve();
return 0;
}