打卡信奥刷题(1584)用C++实现信奥 P6686 混凝土数学

P6686 混凝土数学

题目描述

你正在看混凝土数学,这时旁边的工地开工了,你觉得看他们施工更有意思,于是你向窗外望去,注意到了一些长度不同的木棍。具体而言,你看到了 nnn 条木棍编号为 1,2,3,…,n1,2,3,\ldots,n1,2,3,,n,长度为 a1,a2,a3,…,ana_1,a_2,a_3,\ldots,a_na1,a2,a3,,an。你突发奇想:有多少拿出其中 333 条木棍的方案满足它们能构成等腰三角形呢?你不想要输出的数太大,所以最后的方案要对 998244353998244353998244353 取模。

给出等腰三角形的要求:任意两边之和大于第三边且至少有两条边边长相等。

例如,如果木棍长度分别为 {3,3,2,2,4,5}\{3,3,2,2,4,5\}{3,3,2,2,4,5},你就有 666 种方法,选取的木棍编号分别为:{1,2,3}\{1,2,3\}{1,2,3}{1,2,4}\{1,2,4\}{1,2,4}{1,2,5}\{1,2,5\}{1,2,5}{1,2,6}\{1,2,6\}{1,2,6}{1,3,4}\{1,3,4\}{1,3,4}{2,3,4}\{2,3,4\}{2,3,4}

输入格式

第一行给出一个正整数 nnn 表示木棍个数。

第二行 nnn 个正整数表示 a1,a2,a3,…,ana_1,a_2,a_3,\ldots, a_na1,a2,a3,,an

输出格式

一个数表示总方案数对 998244353998244353998244353 取模的结果。

输入输出样例 #1

输入 #1

6
3 3 2 2 4 5

输出 #1

6

输入输出样例 #2

输入 #2

6
1 1 4 5 1 4

输出 #2

5

输入输出样例 #3

输入 #3

6
2 2 2 2 2 2

输出 #3

20

说明/提示

  • Subtask1 (303030 pts):1≤n≤2001\leq n \leq 2001n200
  • Subtask2 (303030 pts):1≤n≤20001\leq n \leq 20001n2000
  • Subtask3 (202020 pts):木棍长度全部相等。
  • Subtask4 (202020 pts):无特殊限制。

对于 100%100\%100% 的数据满足:1≤n≤2×1051\leq n \leq 2\times 10^51n2×1051≤ai≤2×1051\leq a_i \leq 2\times 10^51ai2×105

C++实现

#include <iostream>
#include <cstdio>
#include <algorithm>
#define mod 998244353
#define ll long long
using namespace std;
const int MAX = 200005;
ll vis[MAX << 1],a[MAX],b[MAX],c[MAX][5],s[MAX << 1],ans,n,k;
int main ()
{
	c[0][0] = c[1][0] = c[1][1] = 1;
	for (int i = 2;i <= 200000;++i)
	{
		c[i][0] = 1;//初始化
		for (int j = 1;j <= min (i,3);++j) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;	
	}
	scanf ("%lld",&n);
	for (int i = 1;i <= n;++i)
	{
		scanf ("%lld",&a[i]);
		if (!vis[a[i]]) b[++k] = a[i];//去重
		vis[a[i]]++;//记录数量
	} 
	sort (b + 1,b + 1 + k);//排序
	for (int i = 1;i < MAX << 1;++i) s[i] = s[i - 1] + vis[i];//前缀和进行预处理
	for (int i = 1;i <= k;++i)
	{
		if(vis[b[i]] >= 3) ans += c[vis[b[i]]][3],ans %= mod;//等边 
		ans += c[vis[b[i]]][2] * (s[b[i] * 2 - 1] - vis[b[i]]),ans %= mod;
	}
	printf ("%lld\n",ans);
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值