题解 P6686 【混凝土数学】
wuyonghuming · · 题解
思路:
这道题目只要枚举,然后优化一下就可以通过了
我们首先把每个长度的棍子的个数都记录下来
我们可以枚举每一个腰的长度,然后我们就要计算能和这两根木棍形成三角形的个数。
当两条边的长度和小于等于第三条边时,三根木棒就能形成三角形
因为两根木棍的长度相同,第三条边的长度一定是一个正整数,所以不存在一个腰加上第三条边的长度和小于另一个腰
所以只有一种情况不能形成三角形:当第三条边的长度大于等于两条腰的和才不能形成三角形
想求出不能和这个长度为腰形成三角形的边的个数,有两种方法
第一种就是从这两条边的长度和开始,一直到最长长度,把它们加起来
显然复杂度过高,会时间超限
第二种方法就是一开始没有能形成三角形的,因为我们的循环枚举腰是从短边开始,所以如果前面的长度和第三条边成立那么后面的长度也和第三条边成立,最后再加上前面的和第三条边不成立,后面的和第三条边成立的个数,最多也就两个
现在我们知道了这个长度的腰能和多少根棍子形成三角形的个数了,我们就可以用乘法原理算出答案了
乘法原理要分类讨论:
等边三角形的个数 和 等腰三角形的个数
假设我们有
我们先把腰的符合的方案数算出来,再把它乘上
我们取第一根棍子有
然后算出来
最后我们算出来
乘上
接着我们算等边三角形的个数,依旧假设有
那么取第一根有
我们得到式子
我们取这几根棒子也有顺序,顺序不同,但还是一种方案
取第一根有
于是我们推出式子
化简得到
加起来就是
除了上面那些还有可以优化的
我们只要枚举到最长的木棍就行了,最好不要看都不看直接一到二十万循环,那些小数据的也会慢
最后提醒一下,每个木棍的长度个数和答案最好用
代码:
代码基本上是目前最短的了,加上快读就是目前最优解
#include <stdio.h>//C语言代码
long long f[200001],ans;//分别是每个长度的个数和答案
int main()
{
int n,m=0,k=0,l=1,a;//分别为木棍个数,最长木棍,符合条件的木棍数,符合条件的最长木棍,木棍长度
scanf("%d",&n);//输入木棍个数
for(int i=1;i<=n;i++)//循环木棍个数次
{
scanf("%d",&a);//输入木棍长度
f[a]++;//这个长度的木棍多了一个
m=m<a?a:m;//更新最长木棍的长度
}
for(int i=1;i<=m;i++)//枚举每一个长度为腰,也不用判断是否是零或者一,因为木棍如果是这些数的话,后面的乘法会让它们变成零
{
for(;l<i*2&&l<=m;l++)//枚举到符合条件的木棍长度
k+=f[l];//符合条件的木棍数加上这个长度的木棍个数
ans+=(f[i]-1)*f[i]*(k-f[i])/2+(f[i]-2)*(f[i]-1)*f[i]/6;//乘法原理
}
printf("%lld",ans%998244353);//输出取模后的答案
return 0;//别忘了
}
谢谢管理审核和大家观赏!