[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\) 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:

  1. 选择第 \(2, 3, 4\) 根小木棍,长度之和为 \(2 + 3 + 4 = 9\),长度最大值为 \(4\);
  2. 选择第 \(2, 4, 5\) 根小木棍,长度之和为 \(2 + 4 + 5 = 11\),长度最大值为 \(5\);
  3. 选择第 \(3, 4, 5\) 根小木棍,长度之和为 \(3 + 4 + 5 = 12\),长度最大值为 \(5\);
  4. 选择第 \(1, 2, 3, 4\) 根小木棍,长度之和为 \(1 + 2 + 3 + 4 = 10\),长度最大值为 \(4\);
  5. 选择第 \(1, 2, 3, 5\) 根小木棍,长度之和为 \(1 + 2 + 3 + 5 = 11\),长度最大值为 \(5\);
  6. 选择第 \(1, 2, 4, 5\) 根小木棍,长度之和为 \(1 + 2 + 4 + 5 = 12\),长度最大值为 \(5\);
  7. 选择第 \(1, 3, 4, 5\) 根小木棍,长度之和为 \(1 + 3 + 4 + 5 = 13\),长度最大值为 \(5\);
  8. 选择第 \(2, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 3 + 4 + 5 = 14\),长度最大值为 \(5\);
  9. 选择第 \(1, 2, 3, 4, 5\) 根小木棍,长度之和为 \(1 + 2 + 3 + 4 + 5 = 15\),长度最大值为 \(5\)

【样例 2 解释】

共有以下 \(6\) 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:

  1. 选择第 \(1, 2, 3\) 根小木棍,长度之和为 \(2 + 2 + 3 = 7\),长度最大值为 \(3\);
  2. 选择第 \(3, 4, 5\) 根小木棍,长度之和为 \(3 + 8 + 10 = 21\),长度最大值为 \(10\);
  3. 选择第 \(1, 2, 4, 5\) 根小木棍,长度之和为 \(2 + 2 + 8 + 10 = 22\),长度最大值为 \(10\);
  4. 选择第 \(1, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 3 + 8 + 10 = 23\),长度最大值为 \(10\);
  5. 选择第 \(2, 3, 4, 5\) 根小木棍,长度之和为 \(2 + 3 + 8 + 10 = 23\),长度最大值为 \(10\);
  6. 选择第 \(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;
}


posted @ 2026-06-24 00:19  yaoxx123  阅读(11)  评论(0)    收藏  举报