HDU 4466 Triangle (边长a+b+c=M的三角形个数->且gcd(a,b,c)=1的三角形个数)

来源:互联网 发布:如何看网络直播 编辑:程序博客网 时间:2024/04/30 04:47

Triangle

Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 627 Accepted Submission(s): 292

Problem Description

You have a piece of iron wire with length of n unit. Now you decide to cut it into several ordered pieces and fold each piece into a triangle satisfying:
*All triangles are integral.
* All triangles are pairwise similar.
You should count the number of different approaches to form triangles. Two approaches are considered different if either of the following conditions is satisfied:
*They produce different numbers of triangles.
* There exists i that the ith (again, pieces are ordered) triangle in one approaches is not congruent to ith triangle in another plan.
The following information can be helpful in understanding this problem.
* A triangle is integral when all sides are integer.
*Two triangles are congruent when all corresponding sides and interior angles are equal.
* Two triangles are similar if they have the same shape, but can be different sizes.
*For n = 9 you have 6 different approaches to do so, namely
(1, 1, 1) (1, 1, 1) (1, 1, 1)
(1, 1, 1) (2, 2, 2)
(2, 2, 2) (1, 1, 1)
(1, 4, 4)
(2, 3, 4)
(3, 3, 3)
where (a, b, c) represents a triangle with three sides a, b, c.

Input

There are several test cases.
For each test case there is a single line containing one integer n (1 ≤ n ≤ 5 * 106).
Input is terminated by EOF.

Output

For each test case, output one line “Case X: Y” where X is the test case number (starting from 1) and Y is the number of approaches, moduled by 109 + 7.

Sample Input

1
2
3
4
5
6
8
9
10
11
12
15
19
20
100
1000

Sample Output

Case 1: 0
Case 2: 0
Case 3: 1
Case 4: 0
Case 5: 1
Case 6: 2
Case 7: 1
Case 8: 6
Case 9: 3
Case 10: 4
Case 11: 10
Case 12: 25
Case 13: 10
Case 14: 16
Case 15: 525236
Case 16: 523080925

Source

2012 Asia Chengdu Regional Contest

=================================================

题解

  • 求边长a+b+c=M的三角形个数
  • 且gcd(a,b,c)=1的三角形个数
  • M长度铁丝围成若干个相似三角形的方案数

解析:

  • 第一步:由于每个符合题意的集合都是由相似三角形组成,把任意符合题意集合S中的每个三角形的三条边a,b,c除以gcd(a,b,c)剩下的部分是一样的。记为w(x)。
    • 若剩下的部分我们叫a’,b’,c’,若M=a+b+c,M’=a’+b’+c’,记k=M/M’,则用M长度的铁丝最多能做k个周长为M’的相似三角形。
    • 以a’+b’+c’这样的三角形为基,用长度为M的铁丝能作出2^(k-1)种不同的集合。
  • 第二步:周长为M且三条边a,b,c 满足 a<=b<=c且gcd(a,b,c)=1的三角形的有多少种?记为g(x)。
    • 这里探讨的三角形,就是第一步中边长为a’,b’,c’的小三角形。
    • 举个例子,周长M=15的三角形的就能由周长为3、5和15的小三角形基组成。w(15) = g(3) * 2^(5-1) + g(5) * 2^(3-1) + g(15) * 2^(1-1);
  • 第三步:周长为M且三条边a,b,c 满足 a<=b<=c的三角形的有多少种?记为f(x)。
    • 举个例子,求f(24):周长M=24的三角形有3,4,6,8,12,24这些小三角形基构成,那么g(24) = f(24) - f(12) - f(6) - f(4) - f(3),减完以后就保证gcd(a,b,c)=1的三角形个数g(24)。
  • 第四步:求f(x)。考虑三角形三条边a,b,c,a<=b<=c。
    • 分b==c和b!=c讨论
      • b==c:由于a<=b==c则a最小为1,c最小为ceil(M/3),所以c 最大为floor((M-1)/2),所以这里一共有(M-1)/2 - M/3 + (M%3?0:1)种
      • b!=c:相当于b <= c-1,就相当于a,b,c-1构成的三角形,这样的三角形有f(M-1)种,还要在f(M-1)中排除其中形如a+b==c+1的三角形,因为若a+b+c=M-1,那a,b,c+1这样的三条边不能构成一个边长为M的三角形,因为不满足a+b>c+1。M-1=a+b+c=2c + 1, M = 2C+2, a+b = c+1 = M/2, 这样的二元组(a,b)有M/2/2对。此时的M必然为偶数,所以M在偶数的情况下要减去这类情况。
#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long LL;const int maxn = 5*1e6 + 10;const int mod = 1000000007;int Pow2[maxn];int f[maxn];int main(){//    freopen("data.in", "r", stdin);    Pow2[0] = 1;    for(int i = 1; i < maxn; i++){//计算周长为i的三角形的个数 a<=b<=c        f[i] = f[i-1] + (i-1)/2 - i/3 + (i%3?0:1);        if (!(i&1)) f[i] -= i/4;        if (f[i] >= mod) f[i] -= mod;        if (f[i] < mod) f[i] += mod;        Pow2[i] = (Pow2[i-1]<<1)%mod;    }    //计算周长为i的三角形的个数 gcd(a,b,c) = 1, a<=b<=c    //若gcd(a,b,c)>1 则可以找到周长等于j且j|i的三角形    //那我们就把这种三角形找出来并且排除    for(int i = 3; i < maxn; i++){        for(int j = i+i; j < maxn; j+=i){            f[j] -= f[i];            if (f[j] < 0) f[j] += mod;        }    }    int n, cas = 1;    LL ans;    while(scanf("%d", &n)!=EOF){        ans = 0;        for(int i = 1; i * i <= n; i++){            if(n % i == 0){                ans = (ans + (LL)f[i]*Pow2[n/i-1])%mod;                if (i*i != n){                    ans = (ans + (LL)f[n/i]*Pow2[i-1])%mod;                }            }        }        printf("Case %d: %I64d\n", cas++, ans);    }    return 0;}

再接再厉。

0 0