loj#2331. 「清华集训 2017」某位歌姬的故事【动态规划】

传送门
解题思路: 【loj#2331. 「清华集训 2017」某位歌姬的故事【动态规划】】将序列离散化后,可以给每个点确定一个取值的上界,那么每一种上届的贡献是独立的,分别求出再相乘即可。
对于一种上界ww ,把对应的点和限制提出,那么对于每个右端点,唯一有用的限制就是左端点最靠右的,记为 L[i]L [ i ] ,再设f[i][j]f [ i ] [ j ]表示到第ii个点,最后一个ww在jj的方案数转移即可。
由于要离散化,所以细节比较多。

#include #define ll long long using namespace std; int getint() { int i=0,f=1; char c; for(c=getchar(); (c!='-')&&(c<'0'||c>'9'); c=getchar()); if(c=='-')c=getchar(),f=-1; for(; c>='0'&&c<='9'; c=getchar())i=(i<<3)+(i<<1)+c-'0'; return i*f; } const int N=1005,INF=1e9,mod=998244353; int T,n,m,A,mx,num,p[N],w[N],t[N],a[N],L[N],f[N][N]; ll ans; struct data{int l,r,w; }q[N]; ll Pow(ll x,int y) { ll res=1; for(; y; y>>=1,x=x*x%mod) if(y&1)res=res*x%mod; return res; } void calc(int W) { num=0; for(int i=1; i<=n; i++)if(a[i]==W) t[++num]=i,L[num]=0,memset(f[num],0,sizeof(f[num])); for(int i=1; i<=m; i++)if(q[i].w==W) { if(!num){ans=-1; return; } int l=lower_bound(t+1,t+num+1,q[i].l)-t; int r=lower_bound(t+1,t+num+1,q[i].r)-t-1; L[r]=max(L[r],l); } f[0][0]=1; for(int i=1; i<=num; i++) { ll v1=Pow(W,p[t[i]+1]-p[t[i]]),v2=Pow(W-1,p[t[i]+1]-p[t[i]]); for(int j=0; j=L[i])f[i][j]=(f[i][j]+f[i-1][j]*v2)%mod; f[i][i]=(f[i][i]+f[i-1][j]*(v1+mod-v2))%mod; } } ll res=0; for(int i=0; i<=num; i++)res=(res+f[num][i])%mod; ans=ans*res%mod; } void solve() { n=getint(),m=getint(),A=getint(); mx=num=0; for(int i=1; i<=m; i++) { q[i].l=getint(),q[i].r=getint()+1,q[i].w=getint(); p[++num]=q[i].l,p[++num]=q[i].r,w[++mx]=q[i].w; } p[++num]=1,p[++num]=n+1,sort(p+1,p+num+1),n=unique(p+1,p+num+1)-p-1; sort(w+1,w+mx+1),mx=unique(w+1,w+mx+1)-w-1; for(int i=1; i<=n; i++)a[i]=INF; for(int i=1; i<=m; i++) { q[i].l=lower_bound(p+1,p+n+1,q[i].l)-p; q[i].r=lower_bound(p+1,p+n+1,q[i].r)-p; for(int j=q[i].l; j

    推荐阅读