luoguP4229某位歌姬的故事
分析
套路部分不多说:离散化之后按权值排序,问题就转化成给若干个限制,最大值是
w
w
w,求方案数。
把区间按右端点排序,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前满足了前
i
i
i个区间,最后一个最大值位置在
j
j
j的方案数。
所有合法的
j
j
j均在
[
L
i
,
R
i
]
[L_i,R_i]
[Li,Ri]之间。
转移的时候枚举当前
j
j
j之前的最后一个最大值
k
k
k,
(
k
,
j
)
(k,j)
(k,j)之间填
[
1
,
m
)
[1,m)
[1,m)的数。
f
[
i
]
[
j
]
=
∑
f
[
i
−
1
]
[
k
]
⋅
(
m
−
1
)
j
−
k
−
1
=
(
m
−
1
)
j
−
1
∑
f
[
i
−
1
]
[
k
]
⋅
(
m
−
1
)
−
k
f[i][j]=\sum f[i-1][k] \cdot (m-1)^{j-k-1}=(m-1)^{j-1}\sum f[i-1][k] \cdot (m-1)^{-k}
f[i][j]=∑f[i−1][k]⋅(m−1)j−k−1=(m−1)j−1∑f[i−1][k]⋅(m−1)−k$
前缀和优化一下复杂度就能过了。
具体转移的时候由于有离散化还要稍微处理一下。
离散化之后每个
j
j
j表示的是某个区间内的所有数,为了方便记得把区间右端点
r
r
r和
r
+
1
r+1
r+1也塞进去离散化好进行区间操作。
具体看代码吧。
代码
#include<bits/stdc++.h>
const int N = 2e3 + 10, P = 998244353;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int f[2][N], g[2][N], iv[N], s[N], t[N], L[N], R[N], b[N], val[N], id[N], tp, cnt, n, _n, Q, A;
int fix(int x) {return (x >> 31 & P) + x;}
int add(int a, int b) {return a += b, a >= P ? a - P : a;}
int mul(int a, int b) {return 1LL * a * b % P;}
struct Que {
int l, r, m;
}q[N];
bool cmp(const Que &a, const Que &b) {
return a.m == b.m ? a.r < b.r : a.m < b.m;
}
int Pow(int x, int k) {
int r = 1; k %= P - 1; if(k < 0) k += P - 1;
for(;k; x = mul(x, x), k >>= 1)
if(k & 1)
r = mul(r, x);
return r;
}
int Dp(int m) {
if(m == 1) return 1;
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
int c = 0;
f[0][0] = g[0][0] = 1; iv[0] = 1;
for(int i = 1;i <= cnt; ++i) {
g[c][i] = g[c][i - 1];
s[i] = s[i - 1] + t[i];
iv[i] = Pow(m - 1, -s[i]);
}
for(int i = 1;i <= tp; ++i) {
c ^= 1;
for(int j = 0;j < L[i]; ++j)
f[c][j] = g[c][j] = 0;
for(int j = L[i]; j <= R[i]; ++j) {
f[c][j] = f[c ^ 1][j];
if(j > R[i - 1])
f[c][j] = add(f[c][j], mul(
mul(Pow(m - 1, s[R[i - 1]]), Pow(m, s[j - 1] - s[R[i - 1]])),
mul(g[c ^ 1][R[i - 1]], fix(Pow(m, t[j]) - Pow(m - 1, t[j])))
));
g[c][j] = add(g[c][j - 1], mul(f[c][j], iv[j]));
}
for(int j = R[i] + 1; j <= cnt; ++j)
g[c][j] = g[c][j - 1], f[c][j] = 0;
}
return mul(g[c][cnt], Pow(m - 1, s[cnt]));
}
int F(int x) {return std::lower_bound(b + 1, b + _n + 1, x) - b;}
int Work() {
memset(val, 0, sizeof(val));
n = ri(); Q = ri(); A = ri(); _n = 0;
for(int i = 1;i <= Q; ++i) {
int l = ri(), r = ri(), m = ri();
q[i] = (Que){l, r, m};
b[++_n] = l; b[++_n] = r;
if(r != n) b[++_n] = r + 1;
}
b[++_n] = 1; b[++_n] = n;
std::sort(b + 1, b + _n + 1);
_n = std::unique(b + 1, b + _n + 1) - b - 1;
std::sort(q + 1, q + Q + 1, cmp);
for(int i = 1;i <= Q; ++i) {
q[i].l = F(q[i].l); q[i].r = F(q[i].r);
bool flag = false; int mx = 0;
for(int j = q[i].l; j <= q[i].r; ++j)
if(!val[j])
val[j] = q[i].m, flag = true;
else mx = std::max(mx, val[j]);
if(!flag && mx < q[i].m) return 0;
}
int Ans = 1;
for(int i = 1, j;i <= Q; i = j) {
for(j = i + 1;j <= Q && q[i].m == q[j].m; ++j) ;
cnt = 0;
for(int k = 1;k <= _n; ++k)
if(val[k] == q[i].m)
id[k] = ++cnt, t[cnt] = k == _n ?: b[k + 1] - b[k];
tp = 0;
for(int k = i;k < j; ++k) {
++tp; int l = q[k].l, r = q[k].r;
for(;val[r] != q[i].m;) --r;
for(;val[l] != q[i].m;) ++l;
L[tp] = id[l]; R[tp] = id[r];
}
Ans = mul(Ans, Dp(q[i].m));
}
for(int i = 1;i <= _n; ++i)
if(!val[i])
Ans = mul(Ans, Pow(A, i == _n ?: b[i + 1] - b[i]));
return Ans;
}
int main() {
for(int T = ri();T--;)
printf("%d\n", Work());
return 0;
}