专栏文章

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

P14360题解参与者 4已保存评论 3

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
3 条
当前快照
1 份
快照标识符
@minfkyrw
此快照首次捕获于
2025/12/02 01:36
3 个月前
此快照最后确认于
2025/12/02 01:36
3 个月前
查看原文
背包 dp,应该有绿。
本题解将带领大家走一遍我考场上的思路。
以下的 aa 数组是题目中的 ll 数组。

Solution

很容易想到是 dp,开始猜状态。
dpi,j,kdp_{i,j,k} 表示到了第 ii 个,加和为 jj,第 ii 个选或不选的方案数,答案枚举得。
但是这样有什么问题?我们不能保证这个加和的组成里没有大于 aia_i 的数,怎么办呢?考虑将数组排序一下,这样子会方便许多。
我们接着考虑状态,在这种情况下,设所有数字的加和为 sumsum,很容易想到答案为
i=1nj=ai×2+1sumdpi,j,1\sum_{i=1}^n{\sum_{j=a_i\times 2+1}^{sum}{dp_{i,j,1}}}
为什么这样计算的答案不重不漏呢?因为这样是考虑以每一个 aia_i 为最大值的方案数。
至于转移,其实就是背包 dp 的模版。
dpi,j,1=dpi1,jai,1+dpi1,jai,0dp_{i,j,1}=dp_{i-1,j-a_i,1}+dp_{i-1,j-a_i,0}
这是 7575 分的思路。
考虑优化。
我们发现会超时的原因是 sumsum 太大了,我们思考一下,有必要一直转移到 sumsum 吗,其实只要大于等于最大值 maxnmaxn 的两倍加一也就是 maxn×2+1maxn\times2+1 就一定会产生贡献,因此枚举到 maxn×2+1maxn\times 2+1 就可以了。
但还是 7575 分,内存超限了。
直接滚动数组滚掉就好了。
时间复杂度 O(n×maxi=1nai)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;
}

评论

3 条评论,欢迎与作者交流。

正在加载评论...