UOJ #311「UNR #2」积劳成疾
需要锻炼$ 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 namespace std; 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; }