UOJ#311. 【UNR #2】积劳成疾 动态规划
思路非常巧妙,令 $f[i][j]$ 表示前 $i$ 个数,最大值不大于 $j$ 的权和.
转移的话枚举最大值出现的第一个位置,乘上该位置对应的贡献,然后发现最大值将 $1$ ~ $i$ 分成了两半.
然后两个部分又是互不干扰的子问题,转移一下就行.
把细节都提前考虑清楚后都不用怎么调.
code:
#include <bits/stdc++.h>
#define N 409
#define ll long long
#define mod 998244353
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,K;
int w[N],f[N][N];
int qpow(int x,int y)
{
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod;
return tmp;
}
int main()
{
// setIO("input");
scanf("%d%d",&n,&K);
for(int i=1;i<=n;++i) scanf("%d",&w[i]);
for(int i=0;i<=n;++i) f[0][i]=1;
for(int i=1;i<K;++i)
{
for(int j=1;j<=n;++j)
{
f[i][j]=f[i][j-1];
for(int p=1;p<=i;++p)
(f[i][j]+=(ll)f[p-1][j-1]*f[i-p][j]%mod)%=mod;
}
}
for(int i=K;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
f[i][j]=f[i][j-1];
for(int p=1;p<=i;++p)
(f[i][j]+=(ll)qpow(w[j],min(min(K,i-K+1),min(p,i-p+1)))*f[p-1][j-1]%mod*f[i-p][j]%mod)%=mod;
}
}
printf("%d\n",f[n][n]);
return 0;
}

浙公网安备 33010602011771号