UVA 11401 Triangle Counting

【题意分析】

本题就是在给定的N条边(边长是1,2,3,,,N)里面找合乎要求的三角形个数(任意两条边之和大于第三边)。如果我们直接枚举合乎题意的三角形那么我们不太好出发(想想为什么?),那么我们可以采用补集观念,先找出不合乎要求的三角形数目,再用总的组合数减去不合乎要求的数目,就得最后的结果。那么问题是我们如何枚举不合乎要求的三角形数目呢?我们设三角形的三条边是a,b,c。我们不妨用c表示任意三条边中的边长最大值,那么我们可以得到一个简单的结论:如果能够构成三角形c<a+b.那么当用a和b作为边时,不符合要求的种数为:N-(a+b)+1(此时c>=a+b)。我们不妨令i=a+b。那么对于每一个i,a与b的组合方式有(i-1)/2种方式(仔细想想可以枚举一下有规律)。那么我们可以得到不符要求的组合方式有:(N-(i)+1)*((i-1)/2)种(3<=i<=N).考虑到本题的N可能很大,我们必须用long  long 存储数据。如果直接按照得到的公式从3到N进行相加,那么一定会超时。我们可以通过数学化简的形式简化计算过程使得算法的时间为O(1)。那么如何解决呢?

我们需要考虑i为奇偶数的情况:

当i为奇数(i=2*k+1)时(1<=k<=(N-1)/2),我们可以公式1计算:

 N * sum(n) - 2 * sum2(n);

当i为偶数时(i=2*k+2)时(1<=k<N/2),我们可以采用公式2计算(这里有变换技巧注意体会):

(N + 3) * sum(n) - 2 * sum2(n) - (LL)(N + 1) * n;

其中:

typedef long long LL;
int N;
LL sum(int n)
{
    return (LL)n * (n + 1) / 2;
}
LL sum2(int n)
{
    return (LL) n * (n + 1) * (2 * n + 1) / 6;
}

到这里我们用CN3 减去不符合要求的就行了。

【AC代码】

#include<stdio.h>
#include<string.h>
typedef long long LL;
int N;
LL sum(int n)
{
    return (LL)n * (n + 1) / 2;
}
LL sum2(int n)
{
    return (LL) n * (n + 1) * (2 * n + 1) / 6;
}
int main()
{
    while(scanf("%d", &N), N >= 3)
    {
        LL ans = (LL)N * (N - 1) * (N - 2) / 6;
        int n = N / 2;
        ans -= (N + 3) * sum(n) - 2 * sum2(n) - (LL)(N + 1) * n;
        n = (N - 1) / 2;
        ans -= N * sum(n) - 2 * sum2(n);
        printf("%lld
", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/khbcsu/p/4122287.html