[CSP-J 2025] 多边形 / polygon 题解记录
题意
其实很简单不要被题目长度吓到,就是给你n个数让你选出至少三个数,并且这些数的和>这些数最大值的两倍
思路
这题思路其实你理解了的话就不难 ,但有点难想
看数据范围,对于所有数据n=5000,显然枚举子集的办法根本不行,但我们可以转变一下想法,我们只枚举他的最大值,然后根据他的最大值求出以该数为最大值符合条件的个数可不可呢,但是又有个问题我们怎么求满足条件的数呢?
首先这个数是最大值,那所有其他能选的数都一定<=他,那也就是我们可以给数组排个序,k=1,到n,然后对于每个a[k]就是最大值,选的那些数就从他前面选,但千万不要觉得是枚举的来选,复杂度1秒是承受不不住的,这个时候要聪明一点,还记得前面说到子集吗,我问你1-k个数每个数可选可不选有多少种选择方案?是不是
ok,那剩下的就超级简单了,我们用一个sum = 一到k-1这些数的组成1~a[k]的总方法,那此时sum是不可行的方案总数是吧,那我们怎么知道总方案数呢,其实就是前面说的子集就是总方案数,那合规的就是pow2[k-1]-sum,至于为啥是k-1自己想下,前面说过
AC代码
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 5007, mod = 998244353;
// pow2[i]是前i个数的总共的子集数,f[i]是当前的数能组成i有多少种方法
long long pow2[N], f[N], a[N];
int n;
int main()
{
pow2[0] = 1;
pow2[1] = 2;
cin >> n;
cin >> a[1];
for (int i = 2; i <= n; i++)
{
cin >> a[i];
pow2[i] = pow2[i - 1] * 2 % mod;
}
sort(a + 1, a + 1 + n);
f[0] = 1;
long long ans = 0;
for (int k = 1; k <= n; k++)
{
long long sum = 0;
for (int i = 0; i <= a[k]; i++)
{
sum =(sum+ f[i])%mod;
}
long long sh = (pow2[k - 1] - sum + mod) % mod;
ans += (sh % mod);
for (int i = 5000; i >= a[k]; i--)
{
f[i] = (f[i] + f[i - a[k]]) % mod;
}
}
cout << ans % mod;
return 0;
}
因为前面讲的太详细了就不加注释了哈