2018.12.08【NOIP提高組】模擬B組 JZOJ 5123 diyiti
阿新 • • 發佈:2018-12-13
描述
給定
根長度為
的直的木棍,要從中選出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);
}