hdu 4473 Exam (2012ACM成都赛区现场赛J题)

来源:互联网 发布:淘宝app历史版本 编辑:程序博客网 时间:2024/04/29 17:07
题意:

  定义  f(x) = { num | a*b| x } , 求 \sum { f(x) } , x <= 10^11

思路:

  题目等价于求 a*b*c <= n 的数量.

  假定 a <= b <= c. 则 a <= n^(1/3) , b <= n^(1/2) 

  所以我们可以通过枚举 a,b 计算出数量,时间复杂度未 O(n^(2/3))

  对于枚举的 a, b, c; 有三种情况

  1 . 三个相等  a, a, a 则只需要计算一次 ,  

     数量为:  n^(1/3)

  2.  二个相等,      a, a, b or a, b, b   则需要计算 C(1,3) = 3 次    

    数量为: n/(a*a) - a   and   (n/a)^(1/2) - a

  3.  三个都不相等 a, b, c , 则方案数为 P(3,3) = 6 次

      数量为:    n/(a*b) - b 

  另外要注意的是,  直接用pow(n,m) 求得的值会 四舍五入.要注意  保证 m*m <= n  or  m*m*m <= n 中最大的m


#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<algorithm>using namespace std;__int64 n,m,t,ni,ans,i,j,k;__int64 pow3(__int64 a)//比a的立方根小的最大的整数{    __int64 b=pow(a,1.0/3);    //cout<<b<<endl;    while(b*b*b<a) b++;    while(b*b*b>a) b--;    return b;}__int64 pow2(__int64 a){    __int64 b=pow(a,0.5);    while(b*b<a) b++;    while(b*b>a) b--;    return b;}int main(){    t=0;    while(~scanf("%I64d",&n))    {        t++;        ans=0;        m=pow3(n);//i*j*z<=n 其中i<=j<=z 所以i的最大值是m      //  cout<<m<<endl;        ans+=m;//第一种情况 i*i*i<=n        for(i=1;i<=m;i++)        {            ni=n/i;//第二种情况:1、j*j<=n/i 2、j<=n/i*i            k=pow2(ni);//由上式知 i<=j<=k 得到i j的范围            ans+=(ni/i+k-2*i)*3;//上面1、得到ans=k-(i+1)-1、因为j>i(取=就跟第一种情况相同了) 所以j从i+1取到k该等式都成立 同理得2\ans=ni/i-i            for(j=i+1;j<=k;j++)//第三种情况 c<=n/(i*j) ans=ni/j-j  c取j+1到ni/j再减1(减去跟二重复)                ans+=(ni/j-j)*6;//因为假设是i<=j<=c 而题目没有顺序 每种情况重新排列有6种 所以*6 第二种情况*3同理        }        printf("Case %I64d: %I64d\n",t,ans);    }    return 0;}


原创粉丝点击