题解:P14360 [CSP-J 2025] 多边形 / polygon(民间数据)

· · 题解

背包 dp,应该有绿。

本题解将带领大家走一遍我考场上的思路。

以下的 a 数组是题目中的 l 数组。

Solution

很容易想到是 dp,开始猜状态。

但是这样有什么问题?我们不能保证这个加和的组成里没有大于 $a_i$ 的数,怎么办呢?考虑将数组排序一下,这样子会方便许多。 我们接着考虑状态,在这种情况下,设所有数字的加和为 $sum$,很容易想到答案为 $$ \sum_{i=1}^n{\sum_{j=a_i\times 2+1}^{sum}{dp_{i,j,1}}} $$ 为什么这样计算的答案不重不漏呢?因为这样是考虑以每一个 $a_i$ 为最大值的方案数。 至于转移,其实就是背包 dp 的模版。 $$ dp_{i,j,1}=dp_{i-1,j-a_i,1}+dp_{i-1,j-a_i,0} $$ 这是 $75$ 分的思路。 考虑优化。 我们发现会超时的原因是 $sum$ 太大了,我们思考一下,有必要一直转移到 $sum$ 吗,其实只要大于等于最大值 $maxn$ 的两倍加一也就是 $maxn\times2+1$ 就一定会产生贡献,因此枚举到 $maxn\times 2+1$ 就可以了。 但还是 $75$ 分,内存超限了。 直接滚动数组滚掉就好了。 时间复杂度 $O(n\times \max_{i=1}^na_i)$,可以通过此题。 ## AC code ```cpp #include <bits/stdc++.h> using namespace std; #define int long long const int mod=998244353; int n,a[5005],dp[2][10005][2],ans,maxx; signed main(){ cin>>n; for(int i = 1;i<=n;i++) cin>>a[i],maxx=max(maxx,a[i]); dp[0][0][0]=1; sort(a+1,a+1+n); for(int i = 1;i<=n;i++){ for(int j = 0;j<=maxx*2+1;j++) dp[i&1][j][0]=(dp[i&1^1][j][0]+dp[i&1^1][j][1])%mod, dp[i&1][j][1]=0; for(int j = maxx*2+1;j>=a[i];j--) (dp[i&1][j][1]+=dp[i&1^1][j-a[i]][0]+dp[i&1^1][j-a[i]][1])%=mod; for(int j = maxx*2+2-a[i];j<=maxx*2+1;j++) (dp[i&1][maxx*2+1][1]+=dp[i&1^1][j][0]+dp[i&1^1][j][1])%=mod; for(int j = a[i]*2+1;j<=maxx*2+1;j++) (ans+=dp[i&1][j][1])%=mod; } cout<<ans; return 0; } ```