[CSP-J 2025] 多边形题解

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

题目描述

小 R 喜欢玩小木棍。小 R 有 nnn 根小木棍,第 iii (1≤i≤n1 \leq i \leq n1in) 根小木棍的长度为 aia_iai

小 X 希望小 R 从这 nnn 根小木棍中选出若干根小木棍,将它们按任意顺序首尾相连拼成一个多边形。小 R 并不知道小木棍能拼成多边形的条件,于是小 X 直接将条件告诉了他:对于长度分别为 l1,l2,…,lml_1, l_2, \dots, l_ml1,l2,,lmmmm 根小木棍,这 mmm 根小木棍能拼成一个多边形当且仅当 m≥3m \geq 3m3 且所有小木棍的长度之和大于所有小木棍的长度最大值的两倍,即 ∑i=1mli>2×max⁡i=1mli\sum_{i=1}^{m} l_i > 2 \times \max_{i=1}^{m} l_ii=1mli>2×maxi=1mli

由于小 R 知道了小木棍能拼成多边形的条件,小 X 提出了一个更难的问题:有多少种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形?你需要帮助小 R 求出选出的小木棍能够拼成一个多边形的方案数。两种方案不同当且仅当选择的小木棍的下标集合不同,即存在 1≤i≤n1 \leq i \leq n1in,使得其中一种方案选择了第 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 种选择小木棍的方案,使得选出的小木棍能够拼成一个多边形:

  1. 选择第 2,3,42, 3, 42,3,4 根小木棍,长度之和为 2+3+4=92 + 3 + 4 = 92+3+4=9,长度最大值为 444;
  2. 选择第 2,4,52, 4, 52,4,5 根小木棍,长度之和为 2+4+5=112 + 4 + 5 = 112+4+5=11,长度最大值为 555;
  3. 选择第 3,4,53, 4, 53,4,5 根小木棍,长度之和为 3+4+5=123 + 4 + 5 = 123+4+5=12,长度最大值为 555;
  4. 选择第 1,2,3,41, 2, 3, 41,2,3,4 根小木棍,长度之和为 1+2+3+4=101 + 2 + 3 + 4 = 101+2+3+4=10,长度最大值为 444;
  5. 选择第 1,2,3,51, 2, 3, 51,2,3,5 根小木棍,长度之和为 1+2+3+5=111 + 2 + 3 + 5 = 111+2+3+5=11,长度最大值为 555;
  6. 选择第 1,2,4,51, 2, 4, 51,2,4,5 根小木棍,长度之和为 1+2+4+5=121 + 2 + 4 + 5 = 121+2+4+5=12,长度最大值为 555;
  7. 选择第 1,3,4,51, 3, 4, 51,3,4,5 根小木棍,长度之和为 1+3+4+5=131 + 3 + 4 + 5 = 131+3+4+5=13,长度最大值为 555;
  8. 选择第 2,3,4,52, 3, 4, 52,3,4,5 根小木棍,长度之和为 2+3+4+5=142 + 3 + 4 + 5 = 142+3+4+5=14,长度最大值为 555;
  9. 选择第 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. 选择第 1,2,31, 2, 31,2,3 根小木棍,长度之和为 2+2+3=72 + 2 + 3 = 72+2+3=7,长度最大值为 333;
  2. 选择第 3,4,53, 4, 53,4,5 根小木棍,长度之和为 3+8+10=213 + 8 + 10 = 213+8+10=21,长度最大值为 101010;
  3. 选择第 1,2,4,51, 2, 4, 51,2,4,5 根小木棍,长度之和为 2+2+8+10=222 + 2 + 8 + 10 = 222+2+8+10=22,长度最大值为 101010;
  4. 选择第 1,3,4,51, 3, 4, 51,3,4,5 根小木棍,长度之和为 2+3+8+10=232 + 3 + 8 + 10 = 232+3+8+10=23,长度最大值为 101010;
  5. 选择第 2,3,4,52, 3, 4, 52,3,4,5 根小木棍,长度之和为 2+3+8+10=232 + 3 + 8 + 10 = 232+3+8+10=23,长度最大值为 101010;
  6. 选择第 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.inpolygon/polygon3.anspolygon/polygon3.anspolygon/polygon3.ans

该样例满足测试点 7∼107 \sim 10710 的约束条件。

【样例 4】

见选手目录下的 polygon/polygon4.inpolygon/polygon4.inpolygon/polygon4.inpolygon/polygon4.anspolygon/polygon4.anspolygon/polygon4.ans

该样例满足测试点 11∼1411 \sim 141114 的约束条件。

【子任务】

对于所有测试数据,保证:

  • 3≤n≤5,0003 \leq n \leq 5,0003n5,000;
  • 对于所有 1≤i≤n1 \leq i \leq n1in,均有 1≤ai≤5 0001 \leq a_i \leq 5\,0001ai5000

::cute-table{tuack}

测试点编号n≤n \leqnmax⁡i=1nai≤\max_{i=1}^{n} a_i \leqmaxi=1nai
1∼31 \sim 313333101010
4∼64 \sim 64610101010210^2102
7∼107 \sim 10710202020^
11∼1411 \sim 141114500500500^
15∼1715 \sim 171517^111
18∼2018 \sim 2018205 0005\,0005000^
21∼2521 \sim 252125^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;
}
posted @ 2025-11-03 17:03  bz02_2023f2  阅读(61)  评论(0)    收藏  举报  来源