zoukankan      html  css  js  c++  java
  • hdu 4466 triangle 三角形统计 数学计数

    题意:

      统计长度为n的绳子,截成多个相似三角形,方案数

    思路:

      先整体看此题,  设定一个函数 g(x), 表示周长为x的本质三角形(a,b,c),其 gcd( a,b,c ) = 1, 的数量

      则我们可以知道,  对于长度为 n 的铁丝, 能拆成 n/d 个长度为 d的 本质三角形, d个点,d-1个空隙, 因为可以

    组合,这样得到的三角形两两相似, 方案数就是  g(d) * r^(n/d-1)  . 大意就是利用最小单位的三角形来拼.

    d-1个空隙都有两个选择,取于不取,取则分开,不取则组成成一个大三角形,则最终结果为

        \sum g(d) * r^( n/d-1 )    其中  n%d = 0  

      现在问题就是 如何计算 g(x) . 

      我们再设定一个函数 f(x), 表示周长为 x的不同三角形数量. 其实这里也是用到了 单位长度的概念.

    对于一个本质三角形( gcd(a,b,c) = 1 ) ,  对于 本质三角形 L , a+b+c = L,  则将其扩大d倍,就得到另外一个三角形

    a*d + b*d + c*d = L*d,   显然扩大的三角形 gcd( a*d, b*d, c*d ) = d;  不是本质三角形.  但是我们可以想到  

    f( L*d ) 中包含了 一个 本质三角形 g(L) 通过扩大了d倍.  其实我们就可以得出 f(x) 与 g(x)的关系了.

        f( n )  =  \sum g( d )      其中 n%d = 0

      这个公式看起来很眼熟,  其实可以用 Mobius反演的出  g( n ) = \sum u(d) * f( n/d )  . 但是我们其实也可以不这么做.

    其实我们可以通过线性筛法得出 g(n), 具体如下:

      由上面计算公式,以及前面的分析过程.我们知道.  f(n) 是 包含了一个 g(d) 然后扩充了 n/d 倍得到的. 若从 f(n)中减去所有的g(d),

    其中 d < n, 且 n%d = 0,  则最后剩下那个就是 g(n)了.  所以我们可以 通过线性来求出 g(n).

      现在问题只剩下 如何求出 f(x)了, 若算出f(x),则这道题也就解决了. 而且这里n=1e6, 最好有个O(N)的算法能够得出.

      再重申下 函数f(x),表示周长为 x的不同三角形(a,b,c)的数量,我们假设( a <= b <= c )

      则我们通过枚举最大周长 x, 假设其最大边为 c.

      则问题可以划分为两类 独立:  1: b = c  2: b != c

      第一种情况:  b = c,  则 周长为x的三角形 (a,c,c) 的方案数为:

        因为 a+c+c = x , 且 a <= c 那么

        c最大取  A=floor(   (x-1)/2  ),  c最小取  B=ceil(  x/3  ), 则  此时三角形种类: A-B+1

      第二种情况: b != c,  则 周长为x的三角形 (a,b,c) 的方案数为:

        因为 a+b+c = x, 且 b <= c-1, a+b > c,  

        这里, 我们转而考虑 , 形式如 ( a, b, c-1 ) 的三角形, 其方案数为 f( x-1 ),

    因为 b <= c-1, 又 a+b > c-1, 则当 a+b > c ,则其 就是三角形 (a,b,c)下的不同三角形数量 f(x)了. 

    但是这里有个地方不满足, 就是当 a+b == c,的时候, 假设其为 M , 则我们就可以得出:  f( x ) = f( x-1 ) - M , (b!=c).

        问题就是如何计算出这个M, 我们继续考虑.  

          a+b+(c-1) = x-1,

        => a+b+c = x,  又因为  a+b = c. 可以得到

        =>    c+c = x ,    2*c = x, 所以 c = x/2, 因为c为整数,所以我们知道,只有当x为偶数时才会出现这个M.

        又 a + b = c = x/2,  且 a <= b , 此时 a 的取值为 [ 1, floor( (x/2)/2 ) ]

        所以  当 x为偶数时, M =  floor( (x/2)/2 )

            当 x为奇数时, M = 0;

        通过以上分析, 我们 可以 O(N)计算出 f(x), 再通过线性筛法得出 g(x), 然后枚举 n的因子,计算求出最终结果.

        另外, 这里因为结果较大, 又N = 1e6, 直接开 long long 的数组内存过大, 因为对 1e9+7取余, 我们可以使用int数组,

    注意保证其在int范围内,就好了.

    View Code
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    const int mod = (int)1e9+7;
    const int N = (int)5e6+10;
    typedef long long LL;
    
    int dp[N], fact[N];
    
    void init(){    
        dp[3] = 1;
        for(int n = 4; n < N; n++){
            dp[n] = dp[n-1] + floor((n-1)/2.) - ceil(n/3.) + 1; //case 1;    
            if( !(n&1) ) dp[n] -= floor( (n/2)/2. );
            if( dp[n] < 0 ) dp[n] = dp[n]+mod;
            if( dp[n] >= mod ) dp[n] -= mod;
        }
        fact[1] = 1; fact[2] = 2;
        for(int i = 3; i < N; i++){
            fact[i] = fact[i-1]*2; if(fact[i]>=mod) fact[i]-=mod;
            for(int j = 2; i*j < N; j++){    
                dp[i*j] -= dp[i];
                if( dp[i*j] < 0 ) dp[i*j] += mod;    
            }    
        }
    }
    int main(){
        init();
        int n, Case = 1;
        while( scanf("%d",&n) != EOF){
            LL res = 0;    
            for(int i = 1; i*i <= n; i++){
                if( n%i == 0 ){
                    res = (res + 1LL*dp[i]*fact[(n/i)]%mod )%mod;    
                    if( i*i != n )
                        res = (res + 1LL*dp[n/i]*fact[i]%mod )%mod; 
                }    
            }    
            printf("Case %d: %lld\n", Case++, res );    
        }
        return 0;
    }
  • 相关阅读:
    luogu P1833 樱花 看成混合背包
    luogu P1077 摆花 基础记数dp
    luogu P1095 守望者的逃离 经典dp
    Even Subset Sum Problem CodeForces
    Maximum White Subtree CodeForces
    Sleeping Schedule CodeForces
    Bombs CodeForces
    病毒侵袭持续中 HDU
    病毒侵袭 HDU
    Educational Codeforces Round 35 (Rated for Div. 2)
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/3043446.html
Copyright © 2011-2022 走看看