洛谷P4229 [清華集訓2017] 某位歌姬的故事
阿新 • • 發佈:2020-10-08
不難發現題目中的每個限制可以進行轉化:
\[\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\)
其中 \(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; }