三角形加强版

题目描述

想必学弟学妹们都被小明的三角形坑的不惨吧, 为了锻炼下学弟学妹我决定再补一刀。

让你们来选三角形,有n条边让你选3条边凑成一个三角形,问有多少种可能

比如: 1 2 3 4 这4条边,就有 2 3 4 .这一种可能 。

输入

首先是一个 t , 代表有几组测试数据

接下来一个 n , 代表有多少条边

接下来n个整数代表每条边的长度 l

其中 0 < t <= 10 ,  0 < n <= 1e5 , 0 < l <= 1000

输出

输出方案数

样例输入 
2
4
1 2 3 4
4
3 3 3 3
样例输出 
1
4

 开始的时候看到这题是 一个组合问题,第一想法就是深搜,然而n最大有1e5,而深搜的深度有三层,尽管有优化排除大量情况,但任然不行,

dfs方法(TLE):

#include<stdio.h>
int n, b[10010], t, a[4], sum = 0, flag = 0;
void nb(int x, int y)//快排(从小到大)
{
	if (x >= y)
		return;
	int left, right, temp, t;
	left = x; right = y; temp = b[x];
	while (left < right)
	{
		while (b[right] >= temp && left < right)
			right--;
		while (b[left] <= temp && left < right)
			left++;
		if (left < right)
		{
			t = b[left]; b[left] = b[right]; b[right] = t;
		}
	}
	b[x] = b[left]; b[left] = temp;
	nb(x, left - 1);
	nb(left + 1, y);
	return;
}
void dfs(int x, int y)
{
	
	if (x == 4)//当x等于4时即已经搜索到3条边
	{
		if (a[1] + a[2] > a[3])//满足两条较小边之和大于第三边
			sum++;
		//因为b数组已经从小到大排序了,若出现两条边小于第3边,则后面搜索的第三条边不用再进行判断了,提前结束第三条边的搜索
		else
			flag = 1;
		return;
	}
	for (int i = y; i <= n - 3 + x; i++)
	{
		a[x] = b[i];
		dfs(x + 1, i + 1);
		if (flag == 1)//出现两边之和小于第3边直接提前退出第3条边的搜索
		{
			flag = 0;
			return;
		}
	}
}
int main()
{
	scanf("%d", &t);
	while (t--)
	{
		sum = 0;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
			scanf("%d", &b[i]);
		nb(1, n);//对b数组从小到大排序
		dfs(1, 1);//深度搜索
		printf("%d\n", sum);
	}
	return 0;
}

正确思路

我们注意到,这题边的长度最大只有1000,与搜索每一条边相比,遍历长度反而时间更快了,这里可以用一个数组标记每一个长度出现的次数,再前缀和统计,先嵌套两重循环遍历前两条边较小的边,根据前缀和下标小于前两条边和的长度的边的数量,再相乘即可,注意这里容易出错的地方是三条边中有其中长度相等的情况,这是需要特殊判断一下。

AC代码:

#include<stdio.h>
int main()
{
	long long  n, t, I, i, j;
	scanf("%lld", &t);
	while (t--)
	{
		//book数组标记每个长度出现的次数,min,max找到边中最小的长度和最大的长度
		long long book[2001] = { 0 }, min = 1e9, max = -1e9, dp[3001] = { 0 }, sum = 0;
		scanf("%lld", &n);
		for (i = 1; i <= n; i++)
		{
			scanf("%lld", &I);
			book[I]++;
			if (max < I)//找到最大边的长度
				max = I;
			if (min > I)//找到最小边的长度
				min = I;
		}
		for (i = 1; i <= 2010; i++)//前缀和(注意前缀和的长度一定要大于2000,因为两边之和最大为2000)
		{
				dp[i] = dp[i - 1] + book[i];
		}
		for (i = min; i <= max; i++)//遍历每一个长度
		{
			if (book[i] <= 0)//没有这个长度的边直接跳过
				continue;
			for (j = i+1; j <= max; j++)
			{
				if (book[j] <= 0)
					continue;
				sum += book[i] * book[j] * (dp[i + j - 1] - dp[j]);//三条边长度不同
			}
			if (book[i] >= 2)//三条边有2条长度相同
			{
				sum += book[i] * (book[i] - 1) / 2 * (dp[2 * i - 1] - book[i]);
			}
			if (book[i] >= 3)//三条边长度都相同
			{
				sum += book[i] * (book[i] - 1) * (book[i] - 2) / 6;
			}
		}
		printf("%lld\n", sum);
	}
	return 0;
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 作为一名电子科技专业的自动化方向申请者,我参加了中科大的复试。在复试的C语言上机环节,我们需要完成三道题目。 第一道题是设计程序,输入两个整数,输出它们的乘积。这个题目较为简单,我在Windows下用Dev C++编译器进行了编写,实现了预期的效果。 第二道题是输入9个浮点数,求其中的最大值,输入的浮点数不能超过1e8(10的8次方),且要保留小数点后两位。这个题目比较考验基本功,我初步使用了一个循环,去依次输入并进行比较,然后输出最终的结果。后来发现这个方法有点儿不够优秀,就进行了优化。我使用了一个for循环,在每次输入浮点数时比较大小,将目前最大值存储在一个变量中,最后得到答案。这个方案的速度更快,也符合题目要求。 第三道题是输入多组数据,每组数据输入两个整数,分别表示输入矩阵的行数和列数,之后输入矩阵中的数字,程序结束时输出该矩阵的转置矩阵。这个题目更加复杂,要求会一定的矩阵转置操作,需要由程序自动进行计算。这个题目的程序较长,需要进行判断、循环等操作,我也在这方面进行了充分的练习,最终完成了这道题目。 总的来说,这次复试C语言上机环节让我感到开心和收获颇丰,让我更加熟练掌握了C语言,也让我有信心正式成为中科大的一员。 ### 回答2: 中科大复试c上机回忆 中科大的c语言上机考试共有两道题,第一道题是有关字符串操作的。题目要求从键盘上输入两个字符串,将它们合并在一起,并打印输出。这个题目比较简单,考查了对字符串的掌握程度和对相关函数的使用。 第二道题是有关图形的,要求使用c语言绘制出一个倒三角形。具体思路是从最上层少一个字符的字符串开始,每下降一层就增加两个字符,最后形成倒三角形。这个题目考察了对循环结构和条件判断语句的掌握程度,同时也要求对输出格式的漂亮程度。 总而言之,这次的中科大c语言上机考试难度不算太高,结果主要取决于考生的基础掌握和细致认真的思考。同时,考前要多进行一些模拟练习,增强自己的信心,更好地应对这次考试。 ### 回答3: 中科大复试c上机回忆 在中科大复试中,c语言上机考试是必须要通过的环节之一,考试时间为两个小时。主要考察对算法和数据结构的掌握程度、实现能力和调试能力。 考试题型涉及到链表、树、图等数据结构的实现,需要用c语言完成代码编写和调试。考试时间紧迫,需要快速理解题目要求,尽快实现代码。 我在考试中遇到的主要题目是链表的反转、快排算法、哈希表等,其中哈希表的实现较为复杂,需要考生有较强的理解能力和实现能力。 此外,在考试中,考官也会根据学生的考试表现提出一些进阶问题,涉及到复杂的算法和数据结构。需要考生有较好的理解能力和语言表达能力,并能够通过代码实现相应的算法。 总之,中科大复试c上机考试是对考生实际编程能力和掌握程度的一次全面考查,需要学生充分准备和磨练实战技能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

3分人生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值