版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/84893925
描述
给定
根长度为
的直的木棍,要从中选出6根木棍,满足:能用这6 根木棍拼出一个正方形。注意木棍不能弯折。问方案数。
正方形:四条边都相等、四个角都是直角的四边形。
数据范围:
思路
我们将六根木棍分成4份,那么显然只能是3,1,1,1或2,2,1,1,也就是3条相同的边(以下简称三同边)和两条相同的边(以下简称二同边)
对于有三同边的情况,我们可以枚举这个三同边,再枚举剩余当中的其中1条边,接着通过数组处理出另外两条边之和是否存在即可
对于有二同边的情况,有以下状况
- 当四边相同时
- 剩余两边相同
对于第二种情况,首先枚举二同边,再枚举另外的边,用一个 保存 的个数 的个数(即为剩余两边的方案数)
对于另外的特殊情况,需要更改去重的过程
去重咋去?
首先根据上面说的分为三种情况
- 两边重复的,方案数
- 三边重复的,方案数
- 四边重复的,方案数
根据组合数的性质,这些我们可以 处理,判断的时候 除掉就行
代码
#include<cstdio>
#include<cctype>
#include<algorithm>
#define file(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout)
#define r(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;typedef long long LL;
LL num[10000005],sum[10000005],f[5005],g[5005],h[5005],s[5005],ans,cnt;
int n;
inline char Getchar()
{
static char buf[100000],*p1=buf+100000,*pend=buf+100000;
if(p1==pend)
{
p1=buf; pend=buf+fread(buf,1,100000,stdin);
if (pend==p1) return -1;
}
return *p1++;
}
inline LL read()
{
char c;int d=1;LL f=0;
while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(LL x)
{
if(x<0)write(45),x=-x;
if(x>9)write(x/10);
putchar(x%10+48);
return;
}
signed main()
{
file(yist);
n=read();
r(i,1,n) s[i]=read(),num[s[i]]++;//输入+预处理
sort(s+1,s+1+n);//排序
f[2]=g[3]=h[4]=1;
for(register int i=2;i<n;i++)//预处理
{
if(i>1) f[i+1]=f[i]*(i+1)/(i-1);
if(i>2) g[i+1]=g[i]*(i+1)/(i-2);
if(i>3) h[i+1]=h[i]*(i+1)/(i-3);
}
for(register int i=1;i<n;i++)//剩下三条边中的任意一条边
{
for(register int j=i+1;j<=n;j++)
if(num[s[j]]>=3)//枚举三同边
{
ans+=sum[s[j]-s[i]]*g[num[s[j]]];//加上方案数,由于三同边本身可能会重复算,要乘g
while(s[j+1]==s[j]) j++;//去重
}
for(register int j=1;j<i;j++)
if(s[i]+s[j]<=1e7) sum[s[i]+s[j]]++;//剩下三条变中的剩下两条边
}
n=unique(s+1,s+1+n)-s-1;//去重
for(int i=1;i<=n;i++)
if(num[s[i]]>=2)//枚举二同边
{
cnt=0;
for(int j=i-1;j>0;j--)
{
if(s[j]+s[j]<s[i]) break;//长度不够,组成不了,这里break是配合上面的排序以便减少循环
if(s[j]+s[j]==s[i]){ans+=(h[num[s[j]]]+f[num[s[j]]]*cnt)*f[num[s[i]]];break;}//出现四边相等
ans+=(f[num[s[j]]]*f[num[s[i]-s[j]]]+num[s[j]]*num[s[i]-s[j]]*cnt)*f[num[s[i]]];//正常情况
cnt+=num[s[j]]*num[s[i]-s[j]];
}
}
write(ans);
}