【NOI2017模拟5.31】diyiti

Description
给定n 根直的木棍,要从中选出6 根木棍,满足:能用这6 根木棍拼出一个正方形。注意木棍不能弯折。问方案数。
正方形:四条边都相等、四个角都是直角的四边形。

Input
第一行一个整数n。
第二行包含n 个整数ai,代表每根木棍的长度。

8
4 5 1 5 1 9 4 5

Output
一行一个整数,代表方案数。

3

桶预处理+n^2实现
分类讨论
2 2 1 1 和 3 1 1 1 (数字表示每条边要用到的木棍数)
首先,1即边长是一定要枚举的
2 2 1 1:
2的话我们可以分四种情况讨论:(枚举a)
1:a+a a+a
直接判a*2时候等于边长然后做就可以了
2:a+a b+c
这儿就要用到f数组了(f[i]表示两个木棒组成的长度为i的方案数)
因为f[i]还包含了a+a的情况,所以减去即可
3:a+b a+b
有了a,便可以得到b了
然后判断一下a,b是否都有两个以上
有的话便加到答案里。
4:a+b c+d
这个嘛,就又要用到f数组了
f[边长]记得减去a+b的方案数即可
对了,还有减去c=d的情况哦,哦,哦
3 1 1 1:
3的话我们就不用分情况了
先枚举其中的一条边,然后用f数组得出另外两条的方案数即可
还要减去两个相等的情况
记得特判三个都相等的情况

下面贴代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,a[5010],b[5010][2],tot=1,cnt=0;
int c[10000001],d[20000001];
ll ans=0,s,ww;

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

int main()
{
	freopen("yist.in","r",stdin);
	freopen("yist.out","w",stdout);
	n=read();
	for (int i=1;i<=n;i++)
	{
		a[i]=read();c[a[i]]++;
		for (int j=1;j<i;j++) d[a[i]+a[j]]++;
	} 
	sort(a+1,a+n+1);
	b[tot][0]=a[1],b[tot][1]=1;
	for (int i=2;i<=n;i++)
	{	
		if (a[i]==a[i-1]) b[tot][1]++;
		else b[++tot][0]=a[i],b[tot][1]=1;
	}
	for (int i=1,k;i<=tot;i++)
	{
		if (b[i][1]>=2) // 2 2 1 1
		{
			s=0;k=0;ww=b[i][1]*(b[i][1]-1)>>1;
			if (b[i][0]%2==0) k=(c[b[i][0]>>1])*(c[b[i][0]>>1]-1)>>1;
			for (int j=1;(b[j][0]<<1)<=b[i][0];j++)
				if ((b[j][0]<<1)==b[i][0])
				{
					//a a & a a
					if (b[j][1]>=4) ans+=ww*b[j][1]*(b[j][1]-1)*(b[j][1]-2)*(b[j][1]-3)/24;
					//a a & b c
					if (b[j][1]>=2) ans+=ww*b[j][1]*(b[j][1]-1)*(d[b[i][0]]-(b[j][1]*(b[j][1]-1)>>1))>>1;
				}
				else
				{
					int mid=c[b[i][0]-b[j][0]];
					//a b & a b
					if (b[j][1]>=2 && mid>=2)
						ans+=ww*b[j][1]*(b[j][1]-1)*mid*(mid-1)>>2;
					//a b & c d
					s+=ww*b[j][1]*mid*(d[b[i][0]]-b[j][1]*mid-k);
				}
			ans+=(s>>1);
		}
		if (b[i][1]>=3) // 3 1 1 1
		{
			s=0;ww=b[i][1]*(b[i][1]-1)*(b[i][1]-2)/6;
			for (int j=1;a[j]<b[i][0];j++)
			{
				int mid=b[i][0]-a[j];
				//a a a
				if (a[j]*3==b[i][0]) s+=ww*(d[mid]-c[mid-a[j]]+1);
				else if (mid>a[j]) s+=ww*(d[mid]-c[mid-a[j]]);
				else s+=ww*d[mid];
			}
			ans+=s/3;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Larry1118/article/details/84980132