P4229 某位歌姬的故事 题解
P4229 某位歌姬的故事
Description
\(T\) 次询问,每次给定 \(n,q,A\),求满足以下 \(q\) 条限制且值域在 \(1\sim A\) 的长为 \(n\) 的正整数序列 \(a\) 有多少个:
- 对于第 \(i\) 条限制 \(l_i,r_i,x_i\),要求 \(\max\{a[l],a[l+1] \dots a[r]\}=x\)。
\(1\le T\le20, 1\le n\le10^9, 1\le Q\le500, 1\le A\le10^9, 1\le l_i\le r_i\le n, 1\le x_i\le A\)
Solution
将原序列离散化是必要的,相当于我们拿到了一些有长度的元素,对于这些元素加以限制。
首先将限制按照 \(x_i\) 排序,从小到大考虑限制,\(x_i\) 相同的限制一起考虑。这是因为小的限制强于大的限制,小的限制满足了大的自然就满足了,就不必考虑了。
对于所有 \(x_i\) 不同的限制(也就是我们分开考虑的限制),他们所关心的元素是互不相交的(如果被同时包含了,在较大的限制无需考虑)。因此最终答案就是每一组 \(x_i\) 相同的限制的方案数之积再乘上没有被任何限制所包含的元素的方案数。
接下来的问题就是,对于每一组 \(x_i\) 相同的限制,就它的方案数。
即:对于一些(可以在原序列并不连续的)元素,有一些限制:要求一个连续段的最大值为 \(X\)。
这里使用 \(dp\) 解决。不难想到一个二维 \(dp\):设 \(f_i\) 表示满足了前 \(i\) 个元素所完整包含的限制的方案数,\(g_{i,j}\) 表示填前 \(i\) 个元素,且第 \(j\) 个元素存在 \(X\) 且 \(j+1\sim i\) 的元素不存在 \(X\) 的方案数。
转移(设第 \(i\) 个元素离散化之前长为 \(v_i\)):
-
对于 \(1\le j\le i-1\) 有 \(g_{i,j}=g_i-1,j\times (X-1)^{v_i}\) 表示新的位置可以随便放 \(1\sim X-1\) 的数。
-
\(g_{i,i}=f_{i-1}\times (X^{v_i}-(X-1)^{v_i})\) 表示新的位置放了最大值为 \(X\) 的数。(这里进行了容斥,最大值为 \(X\) 的方案数=放 \(1\sim X\) 减去放 \(1\sim X-1\) 。)
-
设以 \(i\) 结尾的限制中最靠右的左端点为 \(h_i\)。对于 \(1\le j\le h_i-1\) 令 \(g_{i,j}=0\) 表示不允许最后出现 \(X\) 的位置为 \(j\)。
-
\(f_i=\sum g_i\) 。如果截至到 \(i\) 仍然没有限制已经结束,再令 \(f_i+=(X-1)^{\sum v}\)。
朴素 dp 复杂度 \(O(q^2)\)。注意到 g 的转移很优美,使用线段树优化 dp 可以做到 \(O(qlogq)\)。
(然而我前边的分离元素没有好好实现,写成了 \(O(q^2)\))
#include<bits/stdc++.h>
#define N 1005
#define mid ((l+r)>>1)
#define mod 998244353
using namespace std;
int T,n,Q,A,x[N],xt,qt,vis[N],ans,ql,qr,h[N],s[N],st,v[N];
struct node{int l,r,m;}q[N];
int sum[N<<2],tag1[N<<2],tag2[N<<2],f[N];
inline int mo(int x){return x<mod?x:x-mod;}
inline int ksm(int a,int b){
int res=1;
while(b){
if(b&1)res=1ll*res*a%mod;
a=1ll*a*a%mod,b>>=1;
}
return res;
}
inline int ls(int p){return p<<1;}
inline int rs(int p){return p<<1|1;}
inline void F(int p,int l,int r,int t1,int t2){
sum[p]=(1ll*sum[p]*t1+1ll*(r-l+1)*t2)%mod;
tag1[p]=1ll*tag1[p]*t1%mod;
tag2[p]=(1ll*tag2[p]*t1+t2)%mod;
}
inline void push_down(int p,int l,int r){
F(ls(p),l,mid,tag1[p],tag2[p]);
F(rs(p),mid+1,r,tag1[p],tag2[p]);
tag1[p]=1,tag2[p]=0;
}
inline void push_up(int p){sum[p]=mo(sum[ls(p)]+sum[rs(p)]);}
inline void addsum(int p,int l,int r,int L,int R,int t1,int t2){
if(L<=l&&r<=R)return F(p,l,r,t1,t2),void();
push_down(p,l,r);
if(L<=mid)addsum(ls(p),l,mid,L,R,t1,t2);
if(R>mid)addsum(rs(p),mid+1,r,L,R,t1,t2);
push_up(p);
}
inline int getsum(int p,int l,int r,int L,int R){
if(L<=l&&r<=R)return sum[p];
push_down(p,l,r);
int res=0;
if(L<=mid)res=getsum(ls(p),l,mid,L,R);
if(R>mid)res=mo(res+getsum(rs(p),mid+1,r,L,R));
return res;
}
inline void work(){
st=0;int X=q[ql].m;
for(int i=1;i<=xt;i++)if(vis[i]==qt)s[++st]=i,v[st]=x[i]-x[i-1];
for(int i=1;i<=st;i++)h[i]=0;
for(int i=ql;i<=qr;i++){
bool sf=1;
int res,tmp=0x3f3f3f3f;
for(int j=st;j;j--)if(q[i].l<=x[s[j]-1]+1&&x[s[j]]<=q[i].r){
if(sf)sf=0,res=j;
tmp=min(tmp,j);
}
h[res]=max(h[res],tmp);
}
f[0]=1;
addsum(1,1,st,1,st,0,0);
int pre=0;
bool sf=1;
for(int i=1;i<=st;i++){
pre+=v[i];
if(h[i])sf=0;
int r1=ksm(X,v[i]),r2=ksm(X-1,v[i]),r3=(r1-r2+mod)%mod;
if(i!=1)addsum(1,1,st,1,i-1,r2,0);
addsum(1,1,st,i,i,1,1ll*f[i-1]*r3%mod);
if(h[i]!=0&&h[i]!=1)addsum(1,1,st,1,h[i]-1,0,0);
f[i]=mo(getsum(1,1,st,1,i)+(sf?ksm(X-1,pre):0));
}
ans=1ll*ans*f[st]%mod;
}
inline void solve(){
cin>>n>>Q>>A,ans=1;
for(int i=1;i<=Q;i++)cin>>q[i].l>>q[i].r>>q[i].m;
sort(q+1,q+Q+1,[](node x,node y){return x.m<y.m;});
memset(vis,0,sizeof vis);
for(int i=1;i<=Q;i++)x[i*2-1]=q[i].l-1,x[i*2]=q[i].r;
x[Q*2+1]=n,xt=qt=0;
sort(x+1,x+Q*2+2);
for(int i=1;i<=Q*2+1;i++)if(x[i-1]!=x[i])x[++xt]=x[i];
for(int i=1;i<=Q;i++){
if(q[i].m!=q[i-1].m)qt++,ql=i;
bool sf=0;
for(int j=1;j<=xt;j++){
if(!vis[j]&&q[i].l<=x[j-1]+1&&x[j]<=q[i].r)sf=1,vis[j]=qt;
if(vis[j]==qt)sf=1;
}
if(!sf)return cout<<"0\n",void();
if(i==Q||q[i].m!=q[i+1].m)qr=i,work();
}
int tmp=0;
for(int i=1;i<=xt;i++)if(!vis[i])tmp+=x[i]-x[i-1];
tmp=ksm(A,tmp);
ans=1ll*ans*tmp%mod;
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>T;
while(T--)solve();
}

浙公网安备 33010602011771号