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; }