【BZOJ4927】第一題 雙指針+DP(容斥?)
阿新 • • 發佈:2017-06-25
sam ans int 山東 main font 分類 ret 答案
4 5 1 5 1 9 4 5
【BZOJ4927】第一題
Description
給定n根直的木棍,要從中選出6根木棍,滿足:能用這6根木棍拼 出一個正方形。註意木棍不能彎折。問方案數。 正方形:四條邊都相等、四個角都是直角的四邊形。Input
第一行一個整數n。 第二行包含n個整數ai,代表每根木棍的長度。 n ≤ 5000, 1 ≤ ai ≤ 10^7Output
一行一個整數,代表方案數。Sample Input
84 5 1 5 1 9 4 5
Sample Output
3題解:這。。。這不是沈陽集訓的原題嗎?(xqz說是山東集訓的原題)
由於題目讓你拼的是正方形,那麽這個正方形的組成顯然只有兩種情況:3+1+1+1或2+2+1+1(這裏指的是正方形的四條邊),那麽我們分類討論這兩種情況。
如果是2+2+1+1,那麽我們可以枚舉最長的那2根木棍(也就是兩個1的長度)。顯然要先排序,並將長度相同的木棍合在一起。然後我們已知正方形的邊長,那麽問題就變成了如何選出4根木棍a,b,c,d使得a+b=c+d=這個邊長。這裏我采用的是雙指針法。兩個指針從兩段向中間移動,就可以順便統計出有多少對木棍符合條件。於是ans+=C(最長的木棍的條數,2)*C(符合條件的對數,2),當然,別忘了去重!
如果是3+1+1+1,我們依舊是枚舉最長的那3根木棍。然後問題就變成了如何在一堆木棍中選出3根使得長度之和為一個定值。這個顯然是O(n3 )的背包啊,而我們要的是O(n2)的復雜度,怎麽辦?
看來我們枚舉最長棍的做法不太可行,那麽我們可以換個角度,枚舉3條短棍中最長的那一條。那麽我們可以用s[i]表示在之前的木棍中,選出兩根使得長度之和為i的方案數。這樣,我們在枚舉到i的時候,先枚舉i後面的所有木棍j,判斷一下j能否成為最長的木棍,也就是判斷s[j的長度-i的長度]是否為0。如果是,則更新答案;枚舉完j後,我們再用i來更新s數組,這就變成了一個背包問題。
然而考試的時候大佬們都是用容斥來處理的3+1+1+1,感覺容斥學的不好,沒太聽懂~
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; int n,m; ll ans,sum,cnt; int v[5010],val[5010],num[5010],bel[5010]; int s[10000010]; int main() { //freopen("yist.in","r",stdin); //freopen("yist.out","w",stdout); scanf("%d",&n); int i,j,l,r; for(i=1;i<=n;i++) scanf("%d",&v[i]); sort(v+1,v+n+1); for(i=1;i<=n;i++) { if(v[i]>v[i-1]) val[++m]=v[i]; num[m]++,bel[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&&val[l]+val[r]>val[i]) r--; if(val[l]+val[r]!=val[i]||l>r) continue; if(l==r) { if(num[l]>=4) cnt+=(ll)num[l]*(num[l]-1)*(num[l]-2)*(num[l]-3)/2/3/4; cnt+=(ll)num[l]*(num[l]-1)/2*sum; } else { if(num[l]>=2&&num[r]>=2) cnt+=(ll)num[l]*(num[l]-1)/2*num[r]*(num[r]-1)/2; cnt+=(ll)num[l]*num[r]*sum; sum+=(ll)num[l]*num[r]; } } ans+=cnt*num[i]*(num[i]-1)/2; } } for(i=1;i<=n;i++) { for(j=bel[i]+1;j<=m;j++) if(num[j]>=3) ans+=(ll)num[j]*(num[j]-1)*(num[j]-2)/2/3*(s[val[j]-v[i]]); for(j=1;j<i;j++) if(v[j]+v[i]<=v[n]) s[v[j]+v[i]]++; } printf("%lld",ans); return 0; }
【BZOJ4927】第一題 雙指針+DP(容斥?)