UOJ #311「UNR #2」積勞成疾
阿新 • • 發佈:2019-01-10
需要鍛鍊$ DP$能力
題意
等概率產生一個長度為$ n$且每個數在[1,n]間隨機的數列
定義其價值為所有長度為$ k$的連續子數列的最大值的乘積
給定$ n,k$求所有合法數列的價值和
題解
設$ f(x,y)$表示長度為$x$的數列中,最值不超過$ y$的所有數列的價值和
若數列的最值不是$ y$則$ f(x,y)=f(x,y-1)$
否則列舉最左邊的最值位置,設為位置$ i$
則$ f(x,y)$可由$f(i-1,y-1)·w(y)^{calc(i)}·f(x-i,y)$轉移過來
其中$ calc(i)$表示在長度為$ x$的數列中有多少個長度為$ k$的數列包含第$ i$個位置
時間複雜度$ O(n^3)$
程式碼
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<vector> #define p 998244353 #define rt register int #define ll long long using namespacestd; inline ll read(){ ll x=0;char zf=1;char ch=getchar(); while(ch!='-'&&!isdigit(ch))ch=getchar(); if(ch=='-')zf=-1,ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}void writeln(const ll y){write(y);putchar('\n');} int k,m,n,x,y,z,cnt,ans; int w[405]; int calc(int x,int y){ int L=max(1,x-m+1),R=min(x,y-m+1); return max(0,R-L+1); } int f[405][405],mi[405][405]; int main(){ n=read();m=read(); for(rt i=1;i<=n;i++)w[i]=read(); for(rt i=0;i<=n;i++)f[0][i]=1; for(rt i=1;i<=n;i++){ mi[i][0]=1; for(rt j=1;j<=n;j++)mi[i][j]=1ll*mi[i][j-1]*w[i]%p; } for(rt i=1;i<=n;i++) for(rt j=1;j<=n;j++){ if(j>1)f[i][j]=f[i][j-1]; for(rt k=1;k<=i;k++)(f[i][j]+=1ll*f[k-1][j-1]*f[i-k][j]%p*mi[j][calc(k,i)]%p)%=p; } cout<<f[n][n]; return 0; }