题解 P3799 【妖梦拼木棒】
因为聪明,所以我才橙名。小学生又来发题解了!
题号:P3799
算法:枚举,暴力,数组计数
难度:★★★
开课了!
这道题虽然只是一道枚举的题目,但也还是有点难的。先给大家介绍一下枚举。
枚举,在一个有限的区间里面逐个查找。这里强调一下有限的区间,如:1~100中的正整数,这是一个有限的区间。而1~10中的小数,是一个无限的区间。
这题很容易让人想到四重循环暴力枚举,但是数据不饶人,这样子时间复杂度是O(n^4),而n最大是100000,所以很显然这是不行的。
我们又从数据发现,ai好像比较小,所以我们就应该从ai入手。正三角形他的三条边都一样长,我们要挑四条木棒,说明至少有两条边的长度相等,另外两条边的长度之和等于四条边总长度的三分之一。至于为什么,想必大家都可以自己推理出来。
我们要找哪两根或以上的木棍长度先等,就要使用到数组计数。ai当中从最小的到最大的循环,如果当前位置数组的量大于等于2,就开始从最小的ai到i枚举。至于具体怎样做,大家可以看我的代码上的批注。
注意:统计的时候就要边统计边求余了,不然可能会爆掉。
课讲完了,上代码:
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<string>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iomanip>
using namespace std;
int n,b[5010],a[1000010],minn=1e9,maxx;
long long ans;
const int mod=1e9+7;
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];//输入
minn=min(minn,a[i]);//找出最小的ai
maxx=max(maxx,a[i]);//找出最大的ai
b[a[i]]++;//数组计数
}
for(int i=minn+1; i<=maxx; i++)//这里从最小量+1开始枚举,是因为最小量不可能有两个比它更小的两组成
{
if(b[i]>1)//如果这个数字有一个以上
for(int j=minn; j<=i/2; j++)//开始枚举
if(b[j]>=1&&b[i-j]>=1)//如果他可以被两个比他小的两组成
{
if(j*2!=i)ans=(ans+(b[i]*(b[i]-1)/2)*b[j]*b[i-j]%mod)%mod;//统计
else if(b[j]>1)ans=(ans+((b[i]*(b[i]-1)/2)*(b[j]*(b[j]-1)/2)%mod)%mod)%mod;//统计
}
}
cout<<ans%mod;//输出
return 0;
}
祝大家能AC!