并不对劲的uoj311.[UNR #2]积劳成疾
题目大意
有\(n\)个数\(b_1,...,b_n\),一个数\(m(m\leq n)\)。
定义\(n\)个数\(a_1,...,a_n\)的价值是:\(b_{max(a_1,...,a_m)}\times b_{max(a_2,...,a_{m+1})}\times...\times b_{max(a_{n-m+1},...,a_n)}\)。
\(a_1,...,a_n\)中每个数在\(1,2,3,...,n\)中均匀随机,求价值的期望\(\times n^n\)模998244353。
\(1\leq m\leq n\leq 400;b_i<998244353\)。
题解
价值的期望\(\times n^n\)等于\(a_1,...,a_n\)的所有不同取值方案的价值之和。
可以设\(f(l,r,k)\)表示\(a_l,...,a_r\)这一段中最大值为\(k\)时,所有\(a_l,...,a_r\)的不同取值方案的价值之和。
转移时枚举\(a_l,...,a_r\)中最大值出现的第一个(或最后一个)位置,递归计算左右两边,再计算这个最大值对答案的贡献。
算\(f(l,r,k)\)时,当最大值出现在位置\(x(l< x\leq r)\)时,需要先算出\(f(l,x-1,1)+...+f(l,x-1,k-1)\)。右边也是。
这样总时间复杂度是 \(状态数\times转移时间=\Theta(n^3\times n^2)=\Theta(n^5)\),空间复杂度是\(\Theta(n^3)\),看上去都过不了。
式\(f(l,x-1,1)+...+f(l,x-1,k-1)\)可以前缀和优化。
发现区间相同时,区间端点具体在哪不影响\(f(l,r,k)\),只有区间长度影响\(f(l,r,k)\)。把前两维变成一维。
这样时间复杂度就是\(\Theta(n^3)\)。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 401
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
char ch[20];int f=0;
if(!x){putchar('0'),putchar('\n');return;}
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
const LL mod=998244353;
int n,K,f[maxn][maxn],g[maxn][maxn],w[maxn],pw[maxn][maxn],pw2[maxn][maxn];
inline int mo(int x){return x>=mod?x-mod:x;}
inline int calc(int len,int p,int x)
{
if(len<K)return 1;
return pw[x][min(len-K+1,p)-max(p-K+1,1)+1];
}
void work(int len,int k)
{
if(f[len][k]!=-1)return;
if(len<K){f[len][k]=g[len][k]=pw2[k][len];return;}
f[len][k]=0;
for(int i=1;i<=len;i++)
{
if(i!=len&&k==1)continue;
int tmp=1;
if(i>1)work(i-1,k),tmp=g[i-1][k];
if(i<len)work(len-i,k-1),tmp=(LL)tmp*g[len-i][k-1]%mod;
f[len][k]=mo(f[len][k]+(LL)calc(len,i,k)*tmp%mod);
}
work(len,k-1);g[len][k]=mo(f[len][k]+g[len][k-1]);
return;
}
int main()
{
n=read(),K=read();
rep(i,1,n){w[i]=read();pw[i][0]=pw2[i][0]=1;rep(j,1,n)pw2[i][j]=(LL)pw2[i][j-1]*i%mod,pw[i][j]=(LL)pw[i][j-1]*w[i]%mod;}
rep(l,1,n)rep(k,1,n)f[l][k]=-1;
work(n,n);
write(g[n][n]);
return (~(0-0)+1);
}