题目
题目描述
IA 是一名会唱歌的女孩子。
IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿。这首歌一共有 nn 个音符,第 ii 个音符的音高为 h_ih
i
。IA 的音域是 AA,她只能唱出 1\sim A1∼A 中的正整数音高。因此 1\le h_i\le A1≤h
i
≤A。
在写歌之前,IA 需要确定下这首歌的结构,于是她写下了 QQ 条限制,其中第 ii 条为:编号在 l_il
i
到 r_ir
i
之间的音符的最高音高为 m_im
i
。在确定了结构之后,她就可以开始写歌了。不过她还是想知道,一共有多少种可能的歌曲满足她的所有限制?她听说你还有 9 个月就要去 IOI 了,于是希望你帮她计算一下这个值。
输入格式
从标准输入读入数据。
输入的第一行包含一个整数 TT(T\le 20T≤20),代表测试数据的组数。
每组数据的第一行包含三个正整数 n,Q,An,Q,A。接下来 QQ 行,每行三个整数 l_i,r_i,m_il
i
,r
i
,m
i
,表示一条限制。保证 1\le l_i\le r_i\le n, 1\le m_i\le A1≤l
i
≤r
i
≤n,1≤m
i
≤A。
输出格式
输出到标准输出。
输出文件只有一行,表示可能的歌曲数目。这个数可能很大,请将答案模 998244353998244353 输出。
输入输出样例
输入 #1复制
1
3 2 3
1 2 3
2 3 2
输出 #1复制
3
输入 #2复制
2
4 2 4
1 2 3
2 3 4
7 3 74
3 6 56
2 5 56
3 7 70
输出 #2复制
20
160326468
说明/提示
样例1解释 以下是三种可能的歌曲:(3,1,2),(3,2,1),(3,2,2)(3,1,2),(3,2,1),(3,2,2)。
0
思路
设 f[i][j]f[i][j] 表示表示满足了前 ii 个区间,处理到了位置 jj ,且 jj 上放的是最大值,并且 jj 后不能再出现最大值的方案数。
列出方程后可以发现转移是 O(n)O(n) 的,总复杂度就是 O(n^2logn)
使用前缀和优化将转移变成 O(1),总复杂度变为 O(nlogn)可过。
代码
#include<bits/stdc++.h>
#define N 505
#define mod 998244353
using namespace std;
typedef long long ll;
int T;
int n,m,A;
struct P{
int l,r,h;
}a[N];
int p[N*2],top,up[N*2];
pii b[N*2];
int bin(int x)
{
if(!x) return 0;
return lower_bound(p+1,p+top+1,x)-p;
}
int id[N*2],topx,mx[N*2];
int bin1(int x)
{
int l=1,r=topx,pos=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(id[mid]<=x)
{
pos=mid;
l=mid+1;
}
else r=mid-1;
}
return pos;
}
int bin2(int x)
{
int l=1,r=topx,pos=-1;
while(l<=r)
{
int mid=(l+r)/2;
if(id[mid]>=x)
{
pos=mid;
r=mid-1;
}
else l=mid+1;
}
return pos;
}
int quick_pow(int x,int p)
{
int an=1,po=x;
while(p)
{
if(p&1) an=1ll*an*po%mod;
po=1ll*po*po%mod;
p>>=1;
}
return an;
}
int g1[N*2],g2[N*2],f[N*2],sum[N*2],len[N*2];
int solve(int h)
{
for(int i=1;i<=topx;i++) mx[i]=0;
sort(id+1,id+topx+1);
for(int i=1;i<=m;i++)
{
if(a[i].h==h)
{
int r=bin1(a[i].r),l=bin2(a[i].l);
mx[r]=max(mx[r],l);
}
}
for(int i=1;i<=topx;i++) mx[i]=max(mx[i-1],mx[i]);
for(int i=1;i<=topx;i++) g1[i]=quick_pow(h-1,p[id[i]]-p[id[i]-1]);
for(int i=1;i<=topx;i++) g2[i]=(quick_pow(h,p[id[i]]-p[id[i]-1])-g1[i]+mod)%mod;
for(int i=1;i<=topx;i++) len[i]=p[id[i]]-p[id[i]-1]+len[i-1];
g2[topx+1]=1;
f[0]=1;sum[0]=1;
for(int i=1;i<=topx+1;i++)
{
if(mx[i-1]) f[i]=1ll*(sum[i-1]-1ll*sum[mx[i-1]-1]*quick_pow(h-1,len[i-1]-len[mx[i-1]-1])%mod+mod)*g2[i]%mod;
else f[i]=1ll*sum[i-1]*g2[i]%mod;
sum[i]=(1ll*sum[i-1]*g1[i]+f[i])%mod;
}
return f[topx+1];
}
int ans;
int main()
{
T=read();
while(T--)
{
top=0;ans=1;
n=read();m=read();A=read();
for(int i=1;i<=m;i++)
{
a[i].l=read();a[i].r=read();a[i].h=read();
if(a[i].l!=1) p[++top]=a[i].l-1;
p[++top]=a[i].r;
}
p[++top]=n;
sort(p+1,p+top+1);
top=unique(p+1,p+top+1)-p-1;
for(int i=1;i<=top;i++) up[i]=A;
for(int i=1;i<=m;i++)
{
a[i].l=bin(a[i].l-1)+1;a[i].r=bin(a[i].r);
for(int j=a[i].l;j<=a[i].r;j++) up[j]=min(up[j],a[i].h);
}
int bzx=0;
for(int i=1;i<=m;i++)
{
int bz=1;
for(int j=a[i].l;j<=a[i].r;j++)
if(up[j]==a[i].h) bz=0;
if(bz==1)
{
bzx=1;
break;
}
}
if(bzx)
{
puts("0");
continue;
}
for(int i=1;i<=top;i++) b[i]=mp(up[i],i);
sort(b+1,b+top+1);
for(int i=1;i<=top;i++)
{
topx=0;
int R=i-1;
while(R<top&&b[R+1].fi==b[i].fi)
{
R++;
id[++topx]=b[R].se;
}
ans=1ll*ans*solve(b[i].fi)%mod;
i=R;
}
printf("%d\n",ans);
}
return 0;
}