P4229-某位歌姬的故事【dp】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P4229


1|1题目大意

求有多少个长度为n的序列a,满足i[1,n],ai[1,A],还有Q个限制形如

max{aj}(j[li,ri])=mi

1n,A9×108,1miA,1Q500,1T20


1|2解题思路

首先我们第一步肯定是把每个区间的端点提出来离散化,这样我们的区间数就是O(Q)级别的了。

然后考虑到对于两个有交的区间[l1,r1]限制为m1[l2,r2]限制为m2,在m1<m2时这两个区间交的那一部分显然不会对第二个区间产生影响,因为这个区间肯定合法并且不能是最大值。

那么我们考虑求出每个区间能够到达的最大值limi,然后对一个所有的限制[l,r,w],我们都只需要考虑limi=w的区间。

现在相当于对于每个单独的小区间我们可以选择上到最大值或者没有最大值。然后要求是每个区间至少有一个最大值。

考虑dp,设fi,j表示现在做到第i个区间,上一个顶到最大值的区间是j时的方案,因为我们只处理limi=w的区间,所以一个区间最多被做一次。

时间复杂度:O(TQ2)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=2100,P=998244353; struct node{ ll l,r,w; }q[N]; ll T,n,m,A,tot,cnt,b[N]; ll wc[N],bc[N],lim[N],len[N]; ll f[N][N],rim[N],loc[N],pos[N]; ll power(ll x,ll b){ ll ans=1; while(b){ if(b&1)ans=ans*x%P; x=x*x%P;b>>=1; } return ans; } bool cmp(node x,node y){ if(x.w!=y.w)return x.w<y.w; if(x.l!=y.l)return x.l<y.l; return x.r<y.r; } ll calc(ll w,ll L,ll R){ tot=0; for(ll i=1;i<=cnt;i++){ if(lim[i]==w) loc[++tot]=i,rim[tot]=0; pos[i]=tot; } for(ll i=L;i<=R;i++){ q[i].r=pos[q[i].r]; if(loc[pos[q[i].l]]!=q[i].l) q[i].l=pos[q[i].l]+1; else q[i].l=pos[q[i].l]; rim[q[i].r]=max(rim[q[i].r],q[i].l); } ll r=0;f[0][0]=1; for(ll i=1;i<=tot;i++){ for(ll j=0;j<=i;j++)f[i][j]=0; for(ll j=rim[i];j<i;j++) (f[i][j]+=f[i-1][j]*wc[loc[i]]%P)%=P; for(ll j=0;j<i;j++) (f[i][i]+=f[i-1][j]*bc[loc[i]]%P)%=P; } ll ans=0; for(ll j=0;j<=tot;j++) (ans+=f[tot][j])%=P; return ans; } void solve(){ scanf("%lld%lld%lld",&n,&m,&A); for(ll i=1;i<=m;i++){ scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].w); q[i].r++;b[++cnt]=q[i].l;b[++cnt]=q[i].r; } b[++cnt]=1;b[++cnt]=n+1; sort(b+1,b+1+cnt); sort(q+1,q+1+m,cmp); cnt=unique(b+1,b+1+cnt)-b-1; for(ll i=1;i<=cnt;i++)lim[i]=A+1; for(ll i=1;i<=m;i++){ q[i].l=lower_bound(b+1,b+1+cnt,q[i].l)-b; q[i].r=lower_bound(b+1,b+1+cnt,q[i].r)-b-1; bool flag=false; for(ll j=q[i].l;j<=q[i].r;j++){ if(lim[j]>=q[i].w)flag=true; lim[j]=min(lim[j],q[i].w); } if(!flag){puts("0");return;} } ll ans=1; for(ll i=1;i<cnt;i++){ len[i]=b[i+1]-b[i]; if(lim[i]==A+1)ans=ans*power(A,len[i])%P; wc[i]=power(lim[i]-1,len[i]); bc[i]=(power(lim[i],len[i])-wc[i]+P)%P; } ll L,R=0;cnt--; while(R<m){ L=R+1;R=L; while(R<m&&q[R+1].w==q[L].w)R++; ans=ans*calc(q[L].w,L,R)%P; } printf("%lld\n",ans); return; } signed main() { scanf("%lld",&T); while(T--){ cnt=0;solve(); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15998202.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-03-12 P3793-由乃救爷爷【分块,ST表】
点击右上角即可分享
微信分享提示