可以发现,如果一个限制为
max
i
=
l
r
h
i
=
x
\max_{i=l}^rh_i=x
maxi=lrhi=x ,另一个限制为
max
i
=
a
b
h
i
=
y
\max_{i=a}^bh_i=y
maxi=abhi=y 且
y
<
x
y<x
y<x
那么对于任意的
k
∈
[
l
,
r
]
⋂
[
a
,
b
]
k\in[l,r]\bigcap[a,b]
k∈[l,r]⋂[a,b] ,
h
k
h_k
hk 对
max
i
=
l
r
h
i
\max_{i=l}^rh_i
maxi=lrhi 没有影响
所以如果每个限制的
x
x
x 互不相同,我们可以把区间端点离散化之后,按照
x
x
x 从小到大做
具体地,如果一个限制为
max
i
=
l
r
h
i
=
x
\max_{i=l}^rh_i=x
maxi=lrhi=x 且
[
l
,
r
]
[l,r]
[l,r] 内有
k
k
k 个位置没有
x
x
x 严格更小的限制覆盖
那么答案乘上
x
k
−
(
x
−
1
)
k
x^k-(x-1)^k
xk−(x−1)k
最后乘上不被任何限制区间覆盖的位置的贡献
O
(
m
2
)
O(m^2)
O(m2)
而如果
x
x
x 有相同的,那么把
x
x
x 相同的放在一起做
还是按
x
x
x 从小往大做,设满足
max
i
=
l
r
h
i
=
x
\max_{i=l}^rh_i=x
maxi=lrhi=x 的限制有
s
s
s 个
那么对这
s
s
s 个区间端点再离散化一次,为了保证接下去 DP 的复杂度
注意到区间端点离散化之后,整个序列被分割为
O
(
s
)
O(s)
O(s) 段,且每一段一定完全包含或完全不包含于任意一个满足
max
i
=
l
r
h
i
=
x
\max_{i=l}^rh_i=x
maxi=lrhi=x 的限制区间
[
l
,
r
]
[l,r]
[l,r]
设
c
n
t
i
cnt_i
cnti 表示第
i
i
i 段中有多少个位置没被
x
x
x 严格更小的限制覆盖
DP 状态:
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示处理到前
i
i
i 段,上一个恰好填
x
x
x 的位置在第
j
j
j 段,且所有右端点在前
i
i
i 段内的限制区间都至少包含一个恰好填
x
x
x 的位置的方案数(被覆盖的位置不能填数,其他位置只能填
[
1
,
x
]
[1,x]
[1,x] 内的数)
f
[
0
]
[
0
]
=
1
f[0][0]=1
f[0][0]=1
f
[
i
+
1
]
[
i
+
1
]
+
=
f
[
i
]
[
j
]
×
(
x
c
n
t
i
+
1
−
(
x
−
1
)
c
n
t
i
+
1
)
f[i+1][i+1]+=f[i][j]\times(x^{cnt_{i+1}}-(x-1)^{cnt_{i+1}})
f[i+1][i+1]+=f[i][j]×(xcnti+1−(x−1)cnti+1)
f
[
i
+
1
]
[
j
]
+
=
f
[
i
]
[
j
]
×
(
x
−
1
)
c
n
t
i
+
1
f[i+1][j]+=f[i][j]\times(x-1)^{cnt_{i+1}}
f[i+1][j]+=f[i][j]×(x−1)cnti+1
#include<bits/stdc++.h>template<classT>inlinevoidread(T &res){
res =0;bool bo =0;char c;while(((c =getchar())<'0'|| c >'9')&& c !='-');if(c =='-') bo =1;else res = c -48;while((c =getchar())>='0'&& c <='9')
res =(res <<3)+(res <<1)+(c -48);if(bo) res =~res +1;}template<classT>inline T Max(const T &a,const T &b){return a > b ? a : b;}constint N =505, M =1010, ZZQ =998244353;intqpow(int a,int b){int res =1;while(b){if(b &1) res =1ll* res * a % ZZQ;
a =1ll* a * a % ZZQ;
b >>=1;}return res;}int n, q, A, tot, real[M], Tot, Real[M], f[M][M], s[M], mxr[M], ans;bool vis[M], siv[M];struct node
{int l, r, m;} a[N];inlineboolcomp(node a, node b){return a.m < b.m;}voidsolve(int le,int ri,int num){
Real[1]=1; Real[Tot =2]= tot;for(int i = le; i <= ri; i++)
Real[++Tot]= a[i].l, Real[++Tot]= a[i].r +1;
std::sort(Real +1, Real + Tot +1);
Tot = std::unique(Real +1, Real + Tot +1)- Real -1;for(int i =1; i < tot; i++) siv[i]=0;for(int i = le; i <= ri; i++)for(int j = a[i].l; j <= a[i].r; j++)
siv[j]=1;for(int i =1; i < tot; i++)
s[i]= s[i -1]+(vis[i]||!siv[i]?0: real[i +1]- real[i]),
vis[i]= vis[i]|| siv[i];
f[0][0]=1;for(int i =1; i < Tot; i++) mxr[i]=0;for(int i = le; i <= ri; i++){int r = std::lower_bound(Real +1, Real + Tot +1, a[i].r +1)- Real -1,
l = std::lower_bound(Real +1, Real + Tot +1, a[i].l)- Real;
mxr[r]=Max(mxr[r], l);}for(int i =1; i < Tot; i++){int c0 =qpow(num -1, s[Real[i +1]-1]- s[Real[i]-1]),
c1 =(qpow(num, s[Real[i +1]-1]- s[Real[i]-1])- c0 + ZZQ)% ZZQ;for(int j =0; j <= i; j++) f[i][j]=0;for(int j =0; j < i; j++)
f[i][j]=(1ll* c0 * f[i -1][j]+ f[i][j])% ZZQ,
f[i][i]=(1ll* c1 * f[i -1][j]+ f[i][i])% ZZQ;for(int j =0; j < mxr[i]; j++) f[i][j]=0;}int res =0;for(int i = mxr[Tot -1]; i < Tot; i++)
res =(res + f[Tot -1][i])% ZZQ;
ans =1ll* ans * res % ZZQ;}voidwork(){
ans =1;memset(vis,0,sizeof(vis));read(n);read(q);read(A);for(int i =1; i <= q; i++)read(a[i].l),read(a[i].r),read(a[i].m);
std::sort(a +1, a + q +1, comp);
real[1]=1; real[tot =2]= n +1;for(int i =1; i <= q; i++)
real[++tot]= a[i].l, real[++tot]= a[i].r +1;
std::sort(real +1, real + tot +1);
tot = std::unique(real +1, real + tot +1)- real -1;for(int i =1; i <= q;){int nxt = i;while(nxt <= q && a[i].m == a[nxt].m){
a[nxt].l = std::lower_bound(real +1, real + tot +1, a[nxt].l)- real;
a[nxt].r = std::lower_bound(real +1, real + tot +1,
a[nxt].r +1)- real -1;
nxt++;}solve(i, nxt -1, a[i].m);
i = nxt;}int res =0;for(int i =1; i < tot; i++)if(!vis[i]) res += real[i +1]- real[i];printf("%d\n",1ll* ans *qpow(A, res)% ZZQ);}intmain(){int T;read(T);while(T--)work();return0;}