首页 > 其他分享 >P3799 妖梦拼木棒

P3799 妖梦拼木棒

时间:2024-02-18 20:12:47浏览次数:28  
标签:tmp arr 妖梦 木棒 long int P3799 ans

妖梦拼木棒

题目背景

上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来。

题目描述

有 \(n\) 根木棒,现在从中选 \(4\) 根,想要组成一个正三角形,问有几种选法?

答案对 \(10^9+7\) 取模。

输入格式

第一行一个整数 \(n\)。

第二行往下 \(n\) 行,每行 \(1\) 个整数,第 \(i\) 个整数 \(a_i\) 代表第 \(i\) 根木棒的长度。

输出格式

一行一个整数代表答案。

样例 #1

样例输入 #1

4 
1
1
2
2

样例输出 #1

1

提示

数据规模与约定

  • 对于 \(30\%\) 的数据,保证 \(n \le 5 \times 10^3\)。
  • 对于 \(100\%\) 的数据,保证 \(1 \leq n \le 10^5\),\(1 \le a_i \le 5 \times 10^3\)。

2.题解

2.1 子集枚举

错误思路

看到从n个里面选4个,自然而然想到了子集枚举,但是自己错误估计了范围
由于子集枚举中会用到 1 << n, 而 \(1≤ n ≤10^5\) 所以会产生一个非常大的数,根本无法存储,导致溢出

错误代码

#include<bits/stdc++.h>
using namespace std;

int main(){
	int n;
	long long ans = 0; 
	cin >> n;
	if(n < 4) cout << 0;
	
	vector<int> arr(n);
	for(int i = 0; i < n; i++)
		cin >> arr[i];
	
	long long U = 1 << n;
	for(long long S = 0; S < U; S++){
		if(__builtin_popcount(S) == 4){
			vector<int> tmp;
			for(int i = 0; i < n; i++){
				if(S & (1 << i)) tmp.push_back(arr[i]);
			}
			sort(tmp.begin(), tmp.end());
			if(tmp[0] + tmp[1] == tmp[2] && tmp[2] == tmp[3]) 
				ans++;
//			if((tmp[0] == tmp[1] && tmp[1] == tmp[2]) || (tmp[0] == tmp[1] && tmp[1] == tmp[3]) 
//			|| (tmp[0] == tmp[2] && tmp[2] == tmp[3]) || (tmp[1] == tmp[2] && tmp[2] == tmp[3])	) 
//				ans++;
		}
	} 
//	cout << ans % static_cast<int>(1e9 + 7); // 使用 1e9 表示科学计数法中的 $10^9$,但它是一个 double 类型的浮点数,而不是整数,% 操作符使用时,左右操作数都必须是整数
	cout << ans % 1000000007;	
} 

2.2 循环枚举

思路

由于 0 <= n <= 5000, 且\(1 ≤ a_i ​≤5×10^3\), 火柴长度的范围不是很大,只有5000,所以我们直接用数组存储每种数组出现的次数。
同时记录最小数和最大数,方便后面循环使用。
这里我们最开始的思路是四重循环,分别表示四根火柴棒的长度,但是\(O(n^4)\)时间复杂度过高
我们寻找它们之间的关系,要构成一个等边三角形,首先有两个数一定是相等的,另外两个数的和也和前者相等。
所以我们其实只需要两重循环,分别表示两个作为和的数,并用他们的和去我们的数组中寻找有没有两个以上该长度的火柴棒即可
这里注意一下:
1.对于两个作为和的数,相等和不相等的时候可以分出来讨论一下,也可以不用。
2.第二层循环必定是[i, maxNum],就比如像之前已经找过长度为1和长度为2的火柴棒了,再去找长度为2的火柴棒和长度为1的火柴棒就重复了!!!

代码

#include<bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;

int C(int n, int k){
	if(k == 1) return n;
	else if(k == 2) return n * (n - 1) / 2;
}
int main(){
	int n;
	long long ans = 0; 
	cin >> n;
	if(n < 4) cout << 0;
	
	vector<int> arr(10001);
	int maxNum = 5000, minNum = 0;
	for(int i = 0; i < n; i++){
		int tmp;
		cin >> tmp;
		arr[tmp]++;
		maxNum = max(maxNum, tmp);
		minNum = min(minNum, tmp);
	}
	
	for(int i = minNum; i <= maxNum; i++){
		for(int j = i; j <= maxNum; j++){
			if(i + j > maxNum) break;
			if(i == j){
				if(arr[i << 1] >= 2 && arr[i] >= 2){
					ans = (ans + C(arr[i], 2) * C(arr[i << 1], 2)) % MOD; 					
				}
			}
			else{
				if(arr[i + j] >= 2 && arr[i] >= 1 && arr[j] >= 1){
					ans = (ans + C(arr[i], 1) * C(arr[j], 1) * C(arr[i + j], 2)) % MOD;
				}
			}
		}
	} 
	cout << ans % MOD;	
} 

标签:tmp,arr,妖梦,木棒,long,int,P3799,ans
From: https://www.cnblogs.com/trmbh12/p/18019886

相关文章

  • P3799 妖梦拼木棒
    欲由4根木棒组成一个正三角形,则必有2根长度相等,且另外2根长度之和,等于前2根相等的木棒的长度。#include<cstdio>#include<algorithm>usingLL=longlong;constintN=1e5+5,mod=1e9+7;intn,a[N],cnt[N];intmain(){ scanf("%d",&n); intmin=1e9,......
  • 洛谷题单指南-暴力枚举-P3799 妖梦拼木棒
    原题链接:https://www.luogu.com.cn/problem/P3799题意解读:要选四根木棒拼成等边三角形,必然有两根长度相等,其余两根长度之和等于前两根解题思路:木棒总数最大100000,每根最长5000,因此通过枚举其中两根木棒的长度,计算出另外两根的长度,通过各个长度的木棒数进行选择。设数组h[n]保......
  • P3799 妖梦拼木棒(组合数学)
    P3799妖梦拼木棒又是一道要靠题解的思路的题。(难受)。解题思路首先,由于数据大小在5*1e3以内,数据量在1e5以内。所以用桶排记录无疑是最合适的。(记录下数据的最大值和最小值可以提高运行效率)由题目分析,4个木棒中分三份(每份不为0)必然为1,1,2.其次,我们用循环i遍历数组b[],取b[i]为......
  • AcWing 167. 木棒 (剪枝非常多的一道搜索题
    package算法提高课;importjava.util.Arrays;importjava.util.Scanner;publicclassacw167{staticint[]w;staticboolean[]st;staticintsum,len,n;/***本题剪枝比较多光介绍一下,本代码注释光介绍一下剪枝的大概思路,如果有遗忘或......
  • 木棒
    #include<iostream>#include<string.h>#include<algorithm>usingnamespacestd;constintN=70;intn;intw[N];intsum;boolst[N];intlen;//dfs蹦着跳着......
  • C++算法之旅、02 从木棒切割问题领悟二分法精髓
    172、木棒切割问题https://sunnywhy.com/problem/172题目描述给出n根木棒的长度,现在希望通过切割它们来得到至少k段长度相等的木棒(长度必须是整数),问这些长度相等的木......
  • 木棒
    https://www.acwing.com/problem/content/169/#include<cstring>#include<iostream>#include<algorithm>usingnamespacestd;constintN=70;intn;intw[......
  • [AcWing 167] 木棒
    DFS剪枝点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=1e6+10;intn;intw[N];intsum,len;boolst......