洛谷P4229 [清华集训2017] 某位歌姬的故事

不难发现题目中的每个限制可以进行转化:

\[\large \max_{i=l}^r\{ h_i\}=m \Leftrightarrow \forall i \in [l,r],h_i \leqslant m \and \exist i \in[l,r],h_i=m \]

求出每个位置的上界,得 \(\exist i \in[l,r],h_i=m\) 只可能是上界等于 \(m\) 的位置贡献的,那么考虑对每种上界分别来 \(DP\) 方案数,只要满足每段限制区间至少有一个位置达到上界即可。

\(f_{i,j}\) 为在考虑某一上界的限制下,考虑了上界为该上界的前 \(i\) 个数,最后一个达到上界的数在 \(j\) 位置的方案数,得:

\[\large\begin{aligned} f_{i,j}&=(m-1)^{len_i}f_{i-1,j}\ (lim_i\leqslant j<i) \\ f_{i,i}&=(m^{len_i}-(m-1)^{len_i})\sum_{j=0}^{j<i}f_{i-1,j} \end{aligned} \]

其中 \(len_i\) 为位置 \(i\) 到位置 \(i+1\) 的区间长度,\(lim_i\) 为位置 \(i\) 对应的达到上界的位置最小值。

为方便处理,离散化时采用左闭右开。

复杂度为 \(O(TQ^2)\)

#include<bits/stdc++.h>
#define maxn 2010
#define p 998244353
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
ll T,n,q,a,ans=1,tot1,tot2;
ll s1[maxn],s2[maxn],mx[maxn],lim[maxn],d[maxn],f[maxn][maxn];
struct node
{
    ll l,r,m;
}t[maxn];
ll qp(ll x,ll y)
{
    ll v=1;
    while(y)
    {
        if(y&1) v=v*x%p;
        x=x*x%p,y>>=1;
    }
    return v;
}
ll calc(ll x)
{
    int cnt=0;
    for(int i=1;i<=tot1;++i)
        if(mx[i]==x)
            d[++cnt]=i;
    if(!cnt) return 0;
    for(int i=1;i<=cnt;++i) lim[i]=0;
    for(int i=1;i<=q;++i)
    {
        if(t[i].m!=x) continue;
        ll l,r;
        l=lower_bound(d+1,d+cnt+1,t[i].l)-d;
        r=lower_bound(d+1,d+cnt+1,t[i].r)-d-1;
        lim[r]=max(lim[r],l);
    }
    f[0][0]=1;
    for(int i=1;i<=cnt;++i)
    {
        ll v1=qp(x,s1[d[i]+1]-s1[d[i]]),v2=qp(x-1,s1[d[i]+1]-s1[d[i]]);
        f[i][i]=0;
        for(int j=0;j<i;++j)
        {
            if(j>=lim[i]) f[i][j]=f[i-1][j]*v2%p;
            else f[i][j]=0;
            f[i][i]=(f[i][i]+f[i-1][j]*(v1-v2+p)%p)%p;
        }
    }
    ll v=0;
    for(int i=1;i<=cnt;++i) v=(v+f[cnt][i])%p;
    return v;
}
void solve()
{
    read(n),read(q),read(a),ans=1,tot1=tot2=0;
    for(int i=1;i<=q;++i)
    {
        read(t[i].l),read(t[i].r),read(t[i].m),t[i].r++;
        s1[++tot1]=t[i].l,s1[++tot1]=t[i].r,s2[++tot2]=t[i].m;
    }
    s1[++tot1]=1,s1[++tot1]=n+1;
    sort(s1+1,s1+tot1+1),tot1=unique(s1+1,s1+tot1+1)-s1-1;
    sort(s2+1,s2+tot2+1),tot2=unique(s2+1,s2+tot2+1)-s2-1;
    for(int i=1;i<=tot1;++i) mx[i]=a+1;
    for(int i=1;i<=q;++i)
    {
        t[i].l=lower_bound(s1+1,s1+tot1+1,t[i].l)-s1;
        t[i].r=lower_bound(s1+1,s1+tot1+1,t[i].r)-s1;
        for(int j=t[i].l;j<t[i].r;++j) mx[j]=min(mx[j],t[i].m);
    }
    for(int i=1;i<=tot2;++i) ans=ans*calc(s2[i])%p;
    for(int i=1;i<tot1;++i)
        if(mx[i]==a+1)
            ans=ans*qp(a,s1[i+1]-s1[i])%p;
    printf("%lld\n",ans);
}
int main()
{
    read(T);
    while(T--) solve();
    return 0;
}
posted @ 2020-10-07 21:37  lhm_liu  阅读(247)  评论(0编辑  收藏  举报