2018.12.08【NOIP提高組】模擬B組 5123. diyiti
阿新 • • 發佈:2018-12-31
(File IO): input:yist.in output:yist.out
Time Limits: 2000 ms Memory Limits: 524288 KB Detailed Limits Downloads
Description
給定n 根直的木棍,要從中選出6 根木棍,滿足:能用這6 根木棍拼出一個正方形。注意木棍不能彎折。問方案數。
正方形:四條邊都相等、四個角都是直角的四邊形。
Input
第一行一個整數n。
第二行包含n 個整數ai,代表每根木棍的長度。
Output
一行一個整數,代表方案數。
Sample Input
8
4 5 1 5 1 9 4 5
Sample Output
3
Data Constraint
對於20% 的資料,滿足:n ≤ 30
對於40% 的資料,滿足:n ≤ 200
對於60% 的資料,滿足:n ≤ 1000
對於100% 的資料,滿足:n ≤ 5000; 1 ≤ ai ≤ 10^7
思路: 1.兩種情況分類討論
- (1,1,2,2)
先將a陣列去重變為b,b對應這個數值出現的次數num
列舉i,最長的兩條(1,1)在1~i-1這個區間找合法的兩對,這兩對的和相加都為b[i]
ans+=C(num[i],2)*C(合法對數,2);
可以用兩個指標l,r不斷往中間指,同時記錄合法對數(組
- (1,1,1,3)
不能n^3列舉,怎麼辦呢?
i :1->n 列舉三個短邊中最長的一條,j : i+1 - > n列舉最長的那三條(1,1,1)
這樣就不怕重複了
假如我們有f[x]為到目前元素兩兩配對和為x的方案數
則ans+=C(num[j],3)*s[b[j]-a[i]];(邊長為b[j],已經確定了一條邊i,還剩b[j]-a[i]要湊)
#include<bits/stdc++.h> #define ll long long #define N 5010 #define MAX (ll)(1e7) #define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout); using namespace std; ll n,m,l,r,i,j,ans,cnt,sum; ll a[N],b[N],num[N],id[N],s[MAX]; int main() { open("yist"); scanf("%lld",&n); for(i=1;i<=n;i++)scanf("%lld",&a[i]); sort(a+1,a+1+n); for(i=1;i<=n;i++) { if(a[i]!=a[i-1])b[++m]=a[i]; ++num[m]; id[i]=m; } for(i=1;i<=m;i++) { if(num[i]>=2) { sum=cnt=0; for(l=1,r=i-1;l<=r;l++) { while(l<=r && b[l]+b[r]>b[i])--r; if(l>r|| b[l]+b[r]!=b[i])continue; if(l<r) { if(num[l] >=2 && num[r]>=2)cnt+=(num[l])*(num[l]-1)/2*(num[r])*(num[r]-1)/2; cnt+=num[l]*num[r]*sum; sum+=num[l]*num[r]; } else { if(num[l]>=4)cnt+=num[l]*(num[l]-1)*(num[l]-2)*(num[l]-3)/24; cnt+=num[l]*(num[l]-1)/2*sum; } } ans+=num[i]*(num[i]-1)/2*cnt; } } memset(s,0,sizeof s); for(i=1;i<=n;i++) { for(j=id[i]+1;j<=m;j++)if(num[j]>=3)ans+=num[j]*(num[j]-1)*(num[j]-2)/6*s[b[j]-a[i]]; for(j=1;j<i;j++)if(a[i]+a[j]<a[n])++s[a[i]+a[j]]; } printf("%lld",ans); }