2019 CCPC江西省赛 C HDU 6569 Trap

Avin is studying isosceles trapezoids. An isosceles trapezoid is a convex quadrilateral with two opposite parallel bases, two equal-length legs and positive area. In this problem, we further require that the two legs are not parallel. Given n segments, you are asked to find the number of isosceles trapezoids whose 4 edges are from these segments and the greatest common divisor of their lengths is 1. Two congruent isosceles trapezoids are counted only once.

Input

The first line contains a number n (4 ≤ n ≤ 2, 000). The second line contains n numbers, each of which represents the length of a segment (the length is within [2, 10000]).

Output

Print the number of non-congruent isosceles trapezoids.

Sample Input

5
4 4 2 8 9
6
4 4 4 2 8 9

Sample Output

2
3

题意:给定n条边,找能组成多少个等腰梯形。

大佬的解题链接

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n,tot,pri[maxn],u[maxn],vis[maxn],cnt[maxn],a[maxn];
vector<vector<int> >ve,ve1;
int main()
{
	u[1]=1;
	ve1.resize(maxn);
	for(int i=2;i<maxn;i++)//取得莫比乌斯函数值 
	{
		if(!vis[i])//素数的莫比乌斯值为-1 
		{
			pri[++tot]=i;
			u[i]=-1;
		}
		for(int j=1;j<=tot;j++)
		{
			if(i*pri[j] >= maxn)break;//避免数组越界 
			vis[i*pri[j]]=1;//不是素数 
			if(i % pri[j] == 0)//有平方因子,莫比乌斯值为0。\
			i是pri[j]的倍数,则i*pri[j]一定有一个因子是 pri[j]的平方 
			{
				u[i*pri[j]]=0;
				break;
			}
			else u[i*pri[j]]=-u[i];//奇数个质因子为-1,偶数个质因子为1 
		}
	}
	for(int i=1;i<maxn;i++)//计算每个数的因子 
		for(int j=i;j<maxn;j+=i)
			ve1[j].push_back(i);
	while(scanf("%d",&n)==1)
	{
		ve.resize(maxn);//重新设置大小为maxn 
		memset(cnt,0,sizeof(cnt));//清空,cnt记录每个数出现的个数 
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			cnt[a[i]]++;
			for(auto x : ve1[a[i]])//可以理解为ve记录是否存在倍数 
				ve[x].push_back(a[i]);
		}
		long long ans=0;
		for(int i=1;i<maxn;i++)
		{
			if(ve[i].empty() || u[i]==0)continue; 
			long long tt=0;
			sort(ve[i].begin(),ve[i].end());
			ve[i].erase(unique(ve[i].begin(),ve[i].end()),ve[i].end());//去重 
			int num=ve[i].size();
			for(auto j:ve[i])//枚举上底 
			{
				int l=0,r=0;
				while(l<num && ve[i][l]<j+1)l++;//下底能取的最小值 
				for(auto k:ve[i])//枚举腰 
				{
					if(k != j && cnt[k]>=2)//腰与上底值不同 
					{
						while(r<num-1 && ve[i][r+1]<j+k*2)r++;//下底能取的最大值 
						if(l<num && r<num && l<=r)
						{
							tt+=r-l+1;//下底能取的个数,因为前面有去重,所以不会有重复元素 
							if(ve[i][l]<=k && k<=ve[i][r] && cnt[k]<3)tt--;//下底的值和腰的值相等 
						}
					}
					else if(j==k && cnt[j]>=3)//相同 
					{
						while(r<num-1 && ve[i][r+1]<j+k*2)r++;
						if(l<num && r<num && l<=r)
						{
							tt+=r-l+1;
						}
					}
				}
			}
			ans+=tt*u[i];
		}
		printf("%lld\n",ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值