UOJ#346. 【清华集训2017】某位歌姬的故事 动态规划
原文链接www.cnblogs.com/zhouzhendong/p/UOJ346.html
题解
首先按照 $m_i$ 的大小排个序。
如果某一个区间和一个 m 值比他小的区间有交,那么显然可以将这个区间控制的区域删除掉重合的那一段。
如果一个区间被删没了,那么显然答案为 0 。
在这个处理之后,一个区间可能会变得不连续。那么我们就将它前后相连,变成连续的。
接下来问题变成了对每一种权值的区间算答案。
这个东西离散化之后大力DP即可。
注意特判权值为 1 的区间。
写起来好像有点麻烦。
时间复杂度 $O(Tn^2)$ 。
代码
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb(x) push_back(x) #define mp(x,y) make_pair(x,y) #define fi first #define se second #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I') #define outval(x) printf(#x" = %d\n",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\ For(_v2,L,R)printf("%d ",a[_v2]);puts(""); using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef vector <int> vi; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=1005,mod=998244353; int Pow(int x,int y){ int ans=1; for (;y;y>>=1,x=(LL)x*x%mod) if (y&1) ans=(LL)ans*x%mod; return ans; } void Add(int &x,int y){ if ((x+=y)>=mod) x-=mod; } void Del(int &x,int y){ if ((x-=y)<0) x+=mod; } int n,q,ub; int Ha[N],hs=0; int sum[N],vis[N]; struct S{ int L,R,v; }a[N],b[N][N]; int c[N]; bool cmp(S a,S b){ if (a.v!=b.v) return a.v<b.v; if (a.L!=b.L) return a.L<b.L; return a.R<b.R; } int calc(int n,S *A){ static S a[N]; static int kill[N],len[N],pw0[N],pw1[N],iv0[N],iv1[N]; static int Ha[N],rp[N],dp[N]; int m=0,hs=0; For(i,1,n-1) assert(A[i].L<=A[i+1].L); clr(kill); For(i,1,n) For(j,i+1,n) if (A[i].L<=A[j].L&&A[j].R<=A[i].R) kill[i]=1; For(i,1,n) Ha[++hs]=A[i].L,Ha[++hs]=A[i].R+1; sort(Ha+1,Ha+hs+1); hs=unique(Ha+1,Ha+hs+1)-Ha-1; clr(len); For(i,1,n){ int L=lower_bound(Ha+1,Ha+hs+1,A[i].L)-Ha; int R=lower_bound(Ha+1,Ha+hs+1,A[i].R+1)-Ha; For(j,L+1,R) len[j]=Ha[j]-Ha[j-1]; } For(i,1,n) if (!kill[i]) a[++m]=A[i]; int v=a[1].v; if (v==1) return 1; n=m; pw0[1]=iv0[1]=1; For(i,2,hs){ int tmp=len[i]; pw0[i]=(LL)pw0[i-1]*Pow(v-1,tmp)%mod; pw1[i]=(Pow(v,tmp)-Pow(v-1,tmp)+mod)%mod; iv0[i]=Pow(pw0[i],mod-2); } For(i,1,hs) rp[i]=hs+1; For(i,1,n){ a[i].L=lower_bound(Ha+1,Ha+hs+1,a[i].L)-Ha+1; a[i].R=lower_bound(Ha+1,Ha+hs+1,a[i].R+1)-Ha; For(j,1,a[i].L-1) rp[j]=min(rp[j],a[i].R); } int ans=0; clr(dp),dp[1]=1; For(i,1,hs){ For(j,i+1,rp[i]) Add(dp[j],(LL)dp[i]*pw0[j-1]%mod*iv0[i]%mod*pw1[j]%mod); if (rp[i]==hs+1) Add(ans,(LL)dp[i]*pw0[hs]%mod*iv0[i]%mod); } return ans; } void Solve(){ n=read(),q=read(),ub=read(); clr(Ha),hs=0; For(i,1,q){ a[i].L=read(),a[i].R=read(),a[i].v=read(); Ha[++hs]=a[i].L,Ha[++hs]=a[i].R+1; } Ha[++hs]=1,Ha[++hs]=n+1; sort(Ha+1,Ha+hs+1); hs=unique(Ha+1,Ha+hs+1)-Ha-1; Ha[0]=1; clr(vis); sort(a+1,a+q+1,cmp); int cnt=0; for (int i=1,j;i<=q;i=j+1){ j=i,c[++cnt]=0; while (j<q&&a[j+1].v==a[i].v) j++; For(k,1,hs) sum[k]=sum[k-1]+(vis[k]?0:Ha[k]-Ha[k-1]); For(k,i,j){ int L=a[k].L=lower_bound(Ha+1,Ha+hs+1,a[k].L)-Ha; int R=a[k].R=lower_bound(Ha+1,Ha+hs+1,a[k].R+1)-Ha; if (L==R){ puts("0"); return; } c[cnt]++; b[cnt][c[cnt]].L=sum[L]+1; b[cnt][c[cnt]].R=sum[R]; b[cnt][c[cnt]].v=a[k].v; } For(k,i,j) For(t,a[k].L+1,a[k].R) vis[t]=1; } int ans=1; For(i,2,hs) if (!vis[i]) ans=(LL)ans*Pow(ub,Ha[i]-Ha[i-1])%mod; For(i,1,cnt) ans=(LL)ans*calc(c[i],b[i])%mod; cout<<ans<<endl; } int main(){ int T=read(); while (T--) Solve(); return 0; }