題目
題目描述
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;
}