HDU 4466 Triangle 第二次积分赛C题(思维+简单dp+细心)

来源:互联网 发布:双人無心内事无人知 编辑:程序博客网 时间:2024/05/01 12:44

         题目大意:

         给一根长度为n的铁丝,将它分为若干份,不过需要每一份都相似。

     解题思路:

         先求出周长为n的三角形可以分成多少互质的三角形,然后再用对小三角形插隔板法。

     题目地址: Triangle

/*      长度为n的铁丝折断成若干相似的三角形。      先计算长度为x的铁丝能组成的相似三角形,再dp。*/#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;const int MO = (int)1e9+7;const int N=5000005;int f[N],fac[N];//f(x)表示周长为x的不同三角形(a,b,c)的数量. 令a <= b <= c void cal(){    f[3]=1;    for(int i=4;i<N;i++)    {        f[i]=f[i-1] + (i-1)/2 - i/3 + (i%3?0:1);        /*b<c时,由于a,b,c为三角形,则a,b,c-1也为三角形,故用dp递推,         但是下面要减一个特殊的         b=c时 c(max)=fool((x-1)/2), c(min)=ceil(x/3) 所有情况为c(max)-c(min)+1;         */        if(!(i&1)) f[i]-=i/4; //去掉(i-1+1)/4;        /*a+b==c的时候有a+b+c=x,则x=2*c。只有x为偶数时,这个条件才会出现          a的取值为为(1~x/4)*/        if(f[i]>=MO) f[i]-=MO;        if(f[i]<0) f[i]+=MO;    }    fac[1]=1;fac[2]=2;    for(int i=3;i<N;i++)    {        fac[i]=fac[i-1]<<1;       //fac[i]表示将i个小三角形用插隔板法的数目为fac[i]=2^(i-1)        if(fac[i]>=MO) fac[i]-=MO;        for(int j=2;i*j<N;j++)     //线性筛选本质三角形gcd(a,b,c)=1;        {            int t=i*j;            f[t]-=f[i];            if(f[t]<0) f[t]+=MO;            //f[6]=f[6]-f[3]; f[9]=f[9]-f[3];            //f[8]=f[8]-f[4]; f[12]=f[12]-f[4];        }    }}int main(){    int cas=0,n;    cal();    while(~scanf("%d",&n))    {        __int64 res=0;        for(int i=1;i*i<=n;i++)   //代码优化,由于n到了10^6,n/i=j,则对称的可以得到n/j=i;        {            if(n%i==0)            {               res=(res+(__int64)f[i]*fac[n/i])%MO;               if(i*i!=n)                  res=(res+(__int64)f[n/i]*fac[i])%MO;            }        }        /*for(int i=1;i<=n;i++)            if(n%i==0)               res=(res+(__int64)f[i]*fac[n/i])%MO;          //其实可以写成n/2,不过还是没有sqrt(n)优化的好。        }*/        printf("Case %d: %I64d\n",++cas,(res+MO)%MO);    }    return 0;}