洛谷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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步