1. 程式人生 > >【NOI2017模擬5.31】diyiti

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