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);
}
}