zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    开源控件PullToRefreshGridView的使用(三)
    JS中的运算符 以及变量和输入输出
    HTML中表格
    JS中 事件冒泡与事件捕获
    JS中的循环结构
    UML类图详解
    一步一步生成图片水印
    快速生成缩略图
    ==和Equal()的区别
    屌丝程序人生(下)
  • 原文地址:https://www.cnblogs.com/jz929/p/11817863.html
Copyright © 2011-2022 走看看