P3799 妖梦拼木棒 题解

370 阅读1分钟

题目链接

妖梦拼木棒

思路

四个木棒拼出等边三角形,必定有两个木棒长度相等且等于边长,另外两根长度之和为边长。
数据范围ai5×103a_i \leq 5\times10^3,可以用一个桶统计每种木棍的数量,将木棍按长度排序,去重后枚举每一种木棍,数量大于等于2的木棍可作为一组边长,将边长记为ii,内层循环再从小到大枚举小木棍,长度记为jj,那么另一根小木棍长度为iji-j,根据桶中的信息维护答案。

其他

思路简单,但是写组合数算阶乘的时候取模了,调了两天才过。其实不需要写一个完整的组合数函数,因为题目中只用到Cn2C_n^2。除法不能随便取模。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=1E5+3,M=5E3+3,mod=1E9+7;
typedef long long ll;
int n;
ll ans;
int a[N],t[M];
inline ll read()
{
	ll ret=0;char ch=getchar();
	while(ch<'0' || ch>'9')
		ch=getchar();
	while(ch>='0' && ch<='9')
	{
		ret=ret*10+ch-'0';
		ch=getchar();
	}
	return ret;
}
inline ll fac(ll p)
{
	ll ret=1;
	rep(i,2,p)
	{
		ret=(ret*i);
	}
	return ret;
}
inline ll C(ll fir,ll sec)
{
	ll ret=1;
	ret*=fac(fir);
	ret/=fac(sec);
	ret/=fac(fir-sec);
	return ret%mod;
}
int main()
{
	// freopen("in.in","r",stdin);
	n=read();
	rep(i,1,n)
	{
		a[i]=read();
		++t[a[i]];
	}
	sort(a+1,a+n+1);
	int nn=unique(a+1,a+n+1)-a-1;
	rep(i,1,nn)
	{
		ll cur=a[i];
		if(t[cur]<2ll)
			continue;
		// ll ty=C(t[cur],2ll);
		ll ty=t[cur]*(t[cur]-1)/2;
//		cout<<"::::"<<ty<<endl;
		rep(j,1,i-1)
		{
			ll op=cur-a[j];
			if(a[j]>op)
				break;
			if(a[j]==op)
			{
				// ans=(ans+(t[a[j]]*(t[a[j]]-1)/2)%mod*ty)%mod;
				ans=(ans+(C(t[a[j]],2ll)*ty)%mod)%mod;
				break;
			}
			// ans=(ans+(((t[a[j]]*ty)%mod)*t[cur-a[j]])%mod)%mod;
			ans=(ans+(((t[a[j]]*ty)%mod)*t[op])%mod)%mod;
		}
//		cout<<ans<<endl;
	}
	cout<<ans<<endl;
}