【清華集訓】某位歌姬的故事

題目

題目描述
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章