zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    一些数学证明
    重头再来
    二次函数传参
    神经网络
    准备写点随笔了
    如何做出响应式的页面 (转)
    自适应,响应式,viewport总结
    edm邮件制作规范
    博客园blog模板整理
    git 常用的命令
  • 原文地址:https://www.cnblogs.com/khbcsu/p/4122287.html
Copyright © 2011-2022 走看看