[CSP-J 2025] 多边形题解
P14360 [CSP-J 2025] 多边形 / polygon(民间数据)
题目描述
小 R 喜欢玩小木棍。小 R 有 nnn 根小木棍,第 iii (1≤i≤n1 \leq i \leq n1≤i≤n) 根小木棍的长度为 aia_iai。
小 X 希望小 R 从这 nnn 根小木棍中选出若干根小木棍,将它们按任意顺序首尾相连拼成一个多边形。小 R 并不知道小木棍能拼成多边形的条件,于是小 X 直接将条件告诉了他:对于长度分别为 l1,l2,…,lml_1, l_2, \dots, l_ml1,l2,…,lm 的 mmm 根小木棍,这 mmm 根小木棍能拼成一个多边形当且仅当 m≥3m \geq 3m≥3 且所有小木棍的长度之和大于所有小木棍的长度最大值的两倍,即 ∑i=1mli>2×maxi=1mli\sum_{i=1}^{m} l_i > 2 \times \max_{i=1}^{m} l_i∑i=1mli>2×maxi=1mli。
由于小 R 知道了小木棍能拼成多边形的条件,小 X 提出了一个更难的问题:有多少种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形?你需要帮助小 R 求出选出的小木棍能够拼成一个多边形的方案数。两种方案不同当且仅当选择的小木棍的下标集合不同,即存在 1≤i≤n1 \leq i \leq n1≤i≤n,使得其中一种方案选择了第 iii 根小木棍,但另一种方案未选择。由于答案可能较大,你只需要求出答案对 998,244,353998,244,353998,244,353 取模后的结果。
输入格式
输入的第一行包含一个正整数 nnn,表示小 R 的小木棍的数量。
输入的第二行包含 nnn 个正整数 a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an,表示小 R 的小木棍的长度。
输出格式
输出一行一个非负整数,表示小 R 选出的小木棍能够拼成一个多边形的方案数对 998,244,353998,244,353998,244,353 取模后的结果。
输入输出样例 #1
输入 #1
5
1 2 3 4 5
输出 #1
9
输入输出样例 #2
输入 #2
5
2 2 3 8 10
输出 #2
6
说明/提示
【样例 1 解释】
共有以下 999 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:
- 选择第 2,3,42, 3, 42,3,4 根小木棍,长度之和为 2+3+4=92 + 3 + 4 = 92+3+4=9,长度最大值为 444;
- 选择第 2,4,52, 4, 52,4,5 根小木棍,长度之和为 2+4+5=112 + 4 + 5 = 112+4+5=11,长度最大值为 555;
- 选择第 3,4,53, 4, 53,4,5 根小木棍,长度之和为 3+4+5=123 + 4 + 5 = 123+4+5=12,长度最大值为 555;
- 选择第 1,2,3,41, 2, 3, 41,2,3,4 根小木棍,长度之和为 1+2+3+4=101 + 2 + 3 + 4 = 101+2+3+4=10,长度最大值为 444;
- 选择第 1,2,3,51, 2, 3, 51,2,3,5 根小木棍,长度之和为 1+2+3+5=111 + 2 + 3 + 5 = 111+2+3+5=11,长度最大值为 555;
- 选择第 1,2,4,51, 2, 4, 51,2,4,5 根小木棍,长度之和为 1+2+4+5=121 + 2 + 4 + 5 = 121+2+4+5=12,长度最大值为 555;
- 选择第 1,3,4,51, 3, 4, 51,3,4,5 根小木棍,长度之和为 1+3+4+5=131 + 3 + 4 + 5 = 131+3+4+5=13,长度最大值为 555;
- 选择第 2,3,4,52, 3, 4, 52,3,4,5 根小木棍,长度之和为 2+3+4+5=142 + 3 + 4 + 5 = 142+3+4+5=14,长度最大值为 555;
- 选择第 1,2,3,4,51, 2, 3, 4, 51,2,3,4,5 根小木棍,长度之和为 1+2+3+4+5=151 + 2 + 3 + 4 + 5 = 151+2+3+4+5=15,长度最大值为 555。
【样例 2 解释】
共有以下 666 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:
- 选择第 1,2,31, 2, 31,2,3 根小木棍,长度之和为 2+2+3=72 + 2 + 3 = 72+2+3=7,长度最大值为 333;
- 选择第 3,4,53, 4, 53,4,5 根小木棍,长度之和为 3+8+10=213 + 8 + 10 = 213+8+10=21,长度最大值为 101010;
- 选择第 1,2,4,51, 2, 4, 51,2,4,5 根小木棍,长度之和为 2+2+8+10=222 + 2 + 8 + 10 = 222+2+8+10=22,长度最大值为 101010;
- 选择第 1,3,4,51, 3, 4, 51,3,4,5 根小木棍,长度之和为 2+3+8+10=232 + 3 + 8 + 10 = 232+3+8+10=23,长度最大值为 101010;
- 选择第 2,3,4,52, 3, 4, 52,3,4,5 根小木棍,长度之和为 2+3+8+10=232 + 3 + 8 + 10 = 232+3+8+10=23,长度最大值为 101010;
- 选择第 1,2,3,4,51, 2, 3, 4, 51,2,3,4,5 根小木棍,长度之和为 2+2+3+8+10=252 + 2 + 3 + 8 + 10 = 252+2+3+8+10=25,长度最大值为 101010。
【样例 3】
见选手目录下的 polygon/polygon3.inpolygon/polygon3.inpolygon/polygon3.in 与 polygon/polygon3.anspolygon/polygon3.anspolygon/polygon3.ans。
该样例满足测试点 7∼107 \sim 107∼10 的约束条件。
【样例 4】
见选手目录下的 polygon/polygon4.inpolygon/polygon4.inpolygon/polygon4.in 与 polygon/polygon4.anspolygon/polygon4.anspolygon/polygon4.ans。
该样例满足测试点 11∼1411 \sim 1411∼14 的约束条件。
【子任务】
对于所有测试数据,保证:
- 3≤n≤5,0003 \leq n \leq 5,0003≤n≤5,000;
- 对于所有 1≤i≤n1 \leq i \leq n1≤i≤n,均有 1≤ai≤5 0001 \leq a_i \leq 5\,0001≤ai≤5000。
::cute-table{tuack}
| 测试点编号 | n≤n \leqn≤ | maxi=1nai≤\max_{i=1}^{n} a_i \leqmaxi=1nai≤ |
|---|---|---|
| 1∼31 \sim 31∼3 | 333 | 101010 |
| 4∼64 \sim 64∼6 | 101010 | 10210^2102 |
| 7∼107 \sim 107∼10 | 202020 | ^ |
| 11∼1411 \sim 1411∼14 | 500500500 | ^ |
| 15∼1715 \sim 1715∼17 | ^ | 111 |
| 18∼2018 \sim 2018∼20 | 5 0005\,0005000 | ^ |
| 21∼2521 \sim 2521∼25 | ^ | 5 0005\,0005000 |
思路
首先想到暴力枚举使用,可得40分。
然后考虑优化,使用前后缀背包DP,可以发现,有不成立仅当前后之和小于等与aia_iai所以前后缀背包DP,记录可能性,再给其中一个前缀和,在枚举统计即可,最后直接容斥即可。
代码见下
#include<bits/stdc++.h>
using namespace std;
int n,a[5005],mod=998244353,f[5005][5005],f2[5005][5005],dl=0,de=0,op=0,kl=0;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
f[0][0]=1;
for(int i=0;i<=n-1;i++){
for(int j=5001;j>=0;j--){
f[i+1][j]=f[i][j];
if(j+a[i+1]<=5000){
f[i+1][j+a[i+1]]=(f[i+1][j+a[i+1]]+f[i][j])%mod;
}
else{
f[i+1][5001]=(f[i+1][5001]+f[i][j])%mod;
}
}
}
f2[n+1][0]=1;
for(int i=n+1;i>=2;i--){
for(int j=5001;j>=0;j--){
f2[i-1][j]=f2[i][j];
if(j+a[i-1]<=5000){
f2[i-1][j+a[i-1]]=(f2[i-1][j+a[i-1]]+f2[i][j])%mod;
}
else{
f2[i-1][5001]=(f2[i-1][5001]+f2[i][j])%mod;
}
}
}
for(int i=n+1;i>=1;i--){
for(int j=1;j<=5001;j++){
f2[i][j]=(f2[i][j]+f2[i][j-1])%mod;
}
}
dl=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i]>=a[j]&&i!=j){
dl++;
}
}
}
dl+=n;
for(int i=1;i<=n;i++){
for(int j=0;j<=a[i];j++){
op=(op+(long long)f[i-1][j]*f2[i+1][a[i]-j])%mod;
}
}
de=1;
for(int i=1;i<=n;i++){
de=(de*2)%mod;
}
de-=n*(n-1)/2;
de-=n;
de--;
de=(de+mod)%mod;
//cout<<de<<endl;
kl=(de+dl-op+mod)%mod;
cout<<kl<<endl;
return 0;
}

浙公网安备 33010602011771号