hdu 4466 Triangle (数学)

终于做完了这道题,发一下自己的理解,踩踩~~

题意:给你一个长度n的铁丝,将它弯成一个三角形,或者分成m段,每段组成一个三角形,要求这些三角形相似,问有多少种不同的方案数?

题解:

     设f[x] 表示 三角形三边之和为x 的三角形的个数 ,a b c分别为三角形的三边,并且满足a<=b<=c;

        当b==c时:a=1时c取到最大值为maxx= [(x-1)/2], a=b=c时c取到最小值为minx=ceil(x/3) ,所以总共有maxx-minx+1;

        当b!=c 时:(该题的第一个亮点啊)

             由于 b<c即b<=c-1 三角形(a,b,c-1)也必为一个合理的三角形,则可以由f[x-1] 推到当前符合条件的三角形的个数

             当然还有一种特殊情况需要排除,即 前一个状态里 a+b=c+1 的三角形的个数,推到当前状态可知 a+b=c,a+b+c=x

     则 a+b=c=x/2; a 可以从 1 取到 [(x/2)/2], 共有 [(x/2)/2] 种情况;

     以上我们可以得到f[x] 的所有结果

    怎么样求解题目呢?

    长度为n的铁丝,可以分成d 段(n%d==0) ,每段都可以组成一个小的三角形,也可以将其中的几段合并,构成一个大的并且和小三角形相似的三角形,共有 2^(n.d-1)种组合方式,则最终的结果为    sum( f[d] * ( 2^(n/d-1) ) )

    到这里还没有结束,应为用我们之前计算出来的f[x] 进行计算,答案会偏大,有重复计算,所以  (题目的第二个亮点啊)      

     令f [x] 中计算的三角形a,b,c满足gcd(a,b,c)=1;删选过程很简单,如果n%d==0 则 f[n] 中一定包含着f[d] 中所以三角形扩展 n/d 倍后形成的三角形,减去这部分就可以了; 

    此时这道题就真的完结了!!!

    最后提醒一下,注意取模时超int

#include <iostream>
#include<cstdio>
#include<memory.h>
#include<math.h>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
const unsigned int maxn=5000000+10;
const int MOD=1000000000+7;
unsigned int fac[maxn];
unsigned int f[maxn];
void init()
{
    fac[0]=1;
    fac[1]=2;
    fac[2]=4;
    f[3]=1; f[0]=f[1]=f[2]=0;
    ll s1,s2;
    ll tmp;
    for(int x=4;x<=5000000;x++)
    {
        s1=ceil(x*1.0/3);
        s2=(x-1)/2;
        tmp=(f[x-1]+s2-s1+1)%MOD;
        f[x]=tmp;
        if(x%2==0)
        {
            tmp=(f[x]-(ll)((x/2)/2)+MOD)%MOD;
            f[x]=tmp;
        }
    }
    for(int x=3;x<=5000000;x++)
    {
        fac[x]=(fac[x-1]*2)%MOD;
        for(int y=2;x*y<=5000000;y++)
        {
            tmp=((ll)f[x*y]-f[x]+MOD)%MOD;
            f[x*y]=tmp;
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    init();
    int n,tcase=0;
    while(~scanf("%d",&n))
    {
        printf("Case %d: ",++tcase);
        if(n<3)
        {
            printf("0\n");
            continue;
        }
        else
        {
            ll ans=0;
            for(int i=1;i*i<=n;i++) if(n%i==0)
            {
                ans+=((ll)f[i]*fac[n/i-1])%MOD;
                ans=ans%MOD;
                if(i*i!=n) ans=(ans+((ll)f[n/i]*fac[i-1])%MOD)%MOD;
            }
            printf("%I64d\n",ans);
        }
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值