[CSP-J 2025] 多边形
P14360 [CSP-J 2025] 多边形
题目描述
小 R 喜欢玩小木棍。小 R 有 \(n\) 根小木棍,第 \(i\) (\(1 \leq i \leq n\)) 根小木棍的长度为 \(a_i\)。
小 X 希望小 R 从这 \(n\) 根小木棍中选出若干根小木棍,将它们按任意顺序首尾相连拼成一个多边形。小 R 并不知道小木棍能拼成多边形的条件,于是小 X 直接将条件告诉了他:对于长度分别为 \(l_1, l_2, \dots, l_m\) 的 \(m\) 根小木棍,这 \(m\) 根小木棍能拼成一个多边形当且仅当 \(m \geq 3\) 且所有小木棍的长度之和大于所有小木棍的长度最大值的两倍,即 \(\sum_{i=1}^{m} l_i > 2 \times \max_{i=1}^{m} l_i\)。
由于小 R 知道了小木棍能拼成多边形的条件,小 X 提出了一个更难的问题:有多少种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形?你需要帮助小 R 求出选出的小木棍能够拼成一个多边形的方案数。两种方案不同当且仅当选择的小木棍的下标集合不同,即存在 \(1 \leq i \leq n\),使得其中一种方案选择了第 \(i\) 根小木棍,但另一种方案未选择。由于答案可能较大,你只需要求出答案对 \(998,244,353\) 取模后的结果。
输入格式
输入的第一行包含一个正整数 \(n\),表示小 R 的小木棍的数量。
输入的第二行包含 \(n\) 个正整数 \(a_1, a_2, \dots, a_n\),表示小 R 的小木棍的长度。
输出格式
输出一行一个非负整数,表示小 R 选出的小木棍能够拼成一个多边形的方案数对 \(998,244,353\) 取模后的结果。
输入输出样例 #1
输入 #1
5
1 2 3 4 5
输出 #1
9
输入输出样例 #2
输入 #2
5
2 2 3 8 10
输出 #2
6
说明/提示
【样例 1 解释】
共有以下 \(9\) 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:
- 选择第 \(2, 3, 4\) 根小木棍,长度之和为 \(2 + 3 + 4 = 9\),长度最大值为 \(4\);
- 选择第 \(2, 4, 5\) 根小木棍,长度之和为 \(2 + 4 + 5 = 11\),长度最大值为 \(5\);
- 选择第 \(3, 4, 5\) 根小木棍,长度之和为 \(3 + 4 + 5 = 12\),长度最大值为 \(5\);
- 选择第 \(1, 2, 3, 4\) 根小木棍,长度之和为 \(1 + 2 + 3 + 4 = 10\),长度最大值为 \(4\);
- 选择第 \(1, 2, 3, 5\) 根小木棍,长度之和为 \(1 + 2 + 3 + 5 = 11\),长度最大值为 \(5\);
- 选择第 \(1, 2, 4, 5\) 根小木棍,长度之和为 \(1 + 2 + 4 + 5 = 12\),长度最大值为 \(5\);
- 选择第 \(1, 3, 4, 5\) 根小木棍,长度之和为 \(1 + 3 + 4 + 5 = 13\),长度最大值为 \(5\);
- 选择第 \(2, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 3 + 4 + 5 = 14\),长度最大值为 \(5\);
- 选择第 \(1, 2, 3, 4, 5\) 根小木棍,长度之和为 \(1 + 2 + 3 + 4 + 5 = 15\),长度最大值为 \(5\)。
【样例 2 解释】
共有以下 \(6\) 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:
- 选择第 \(1, 2, 3\) 根小木棍,长度之和为 \(2 + 2 + 3 = 7\),长度最大值为 \(3\);
- 选择第 \(3, 4, 5\) 根小木棍,长度之和为 \(3 + 8 + 10 = 21\),长度最大值为 \(10\);
- 选择第 \(1, 2, 4, 5\) 根小木棍,长度之和为 \(2 + 2 + 8 + 10 = 22\),长度最大值为 \(10\);
- 选择第 \(1, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 3 + 8 + 10 = 23\),长度最大值为 \(10\);
- 选择第 \(2, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 3 + 8 + 10 = 23\),长度最大值为 \(10\);
- 选择第 \(1, 2, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 2 + 3 + 8 + 10 = 25\),长度最大值为 \(10\)。
【样例 3】
见选手目录下的 \(\textit{\textbf{polygon/polygon3.in}}\) 与 \(\textit{\textbf{polygon/polygon3.ans}}\)。
该样例满足测试点 \(7 \sim 10\) 的约束条件。
【样例 4】
见选手目录下的 \(\textit{\textbf{polygon/polygon4.in}}\) 与 \(\textit{\textbf{polygon/polygon4.ans}}\)。
该样例满足测试点 \(11 \sim 14\) 的约束条件。
【子任务】
对于所有测试数据,保证:
- \(3 \leq n \leq 5\,000\);
- 对于所有 \(1 \leq i \leq n\),均有 \(1 \leq a_i \leq 5\,000\)。
::cute-table{tuack}
| 测试点编号 | \(n \leq\) | \(\max_{i=1}^{n} a_i \leq\) |
|---|---|---|
| \(1 \sim 3\) | \(3\) | \(10\) |
| \(4 \sim 6\) | \(10\) | \(10^2\) |
| \(7 \sim 10\) | \(20\) | ^ |
| \(11 \sim 14\) | \(500\) | ^ |
| \(15 \sim 17\) | ^ | \(1\) |
| \(18 \sim 20\) | \(5\,000\) | ^ |
| \(21 \sim 25\) | ^ | \(5\,000\) |
解题思路:从题意可知:设最长边为\(a_{i}\) i为边数 ,剩余的变长和为S=\(a_{1}+a_{2}+...+a_{i-1}\)。可得 当2\(a_{i}\)>S+\(a_{i}\) 可组出i边形,即\(a_{i}>S+a_{i}\)可组出i边形。最朴素的方法就是枚举以每条为最长边的使用可能,这里不难看出当以\(a_{i}\)为最长边时\(a_{1}倒a_{i-1}\)都小于\(a_{i}\),故我可以先对所以边进行排序。此时任取一条边\(a_{i}\),如果\(a_{i}\)是某个正确组合中的最长边,那么其余边一定属于\(a_{1}到a_{i-1}\),那么现在的问题就是求\(a_{1}到a_{i-1}\)拼出和大于\(a_{i}\)的种数。即从集合中挑出一些数,求组成某个和的方案有多少种,这是经典的 01 背包计数问题。但如果我们去求大于\(a_{i}\)的种数显然无法完成,每天边的范围10—到5000极限数据下边和为50004999显然不行,证难则反,如果我们可以求出比\(a_{i}\)小的种数,用总的方案数减去不符合的方案数即位符合要求的方案数。
#include <bits/stdc++.h>
using namespace std;
long long dp[6000];
int n;
long long arr[6000];
long long sum[5000];
long long Mod = 998244353;
int main() {
cin >> n;
long long max1=0;
sum[0]=1;
for (int i = 1; i <= n; i++) {
cin >> arr[i];
sum[i] = (sum[i-1]<<1)%Mod;//括号必须加否则先算1%Mod
max1 = max(max1, arr[i]);
}
sort(arr+1, arr +1+ n);
long long ans = 0;
dp[0] = 1;
for (int i = 1; i <= n; i++) {
long long bad=0;
for (int j = arr[i]; j >=0; j--) {
bad =(bad+dp[j])%Mod;
}
long long good=(sum[i-1]-bad+Mod)%Mod;
ans=(ans+good)%Mod;
for (int j = max1; j >=arr[i]; j--) {
dp[j] = (dp[j]+dp[j-arr[i]]) % Mod;
}
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号