题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=4473
题目意思
定义f(x) = 满足(a * b)|x的有序对(a,b)的个数。
然后输入一个n,求f(1) + f(2) + ... + f(n)
废话不多说,此题的关键在于:
把原题的条件(a * b)|x 转化为 a * b * y = x
然后就很好计算了,就是,输入一个n,计算有多少有序对(a, b ,y)满足a*b*y<=n
不妨设a<=b<=y
则,a<=n^(1/3) , b<=sqrt(n/a)
那么
对于三个数字都相同的情况,只计算一次: i i i
对于三个数字中有两个相同的情况,计算3次: i i j, i j i, j i i
对于均不相同的情况,计算6次: a b y ,a y b ,b a y ,b y a, y a b ,y b a
超时代码:
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cstdlib> #include <cmath> #include <vector> #include <list> #include <deque> #include <queue> #include <iterator> #include <stack> #include <map> #include <set> #include <algorithm> #include <cctype> using namespace std; typedef __int64 LL; const int N=400005; const LL II=1000000007; const int INF=0x3f3f3f3f; const double PI=acos(-1.0); LL pow3(LL n) { LL p=(LL)pow(n,1.0/3); while(p*p*p<=n) p++; while(p*p*p>n) p--; return p; } LL pow2(LL n) { LL p=(LL)pow(n,1.0/2); while(p*p<=n) p++; while(p*p>n) p--; return p; } int main() { LL n; int ca=0; while(~scanf("%I64d",&n)) { LL m,t,ans=0,i,j,k; m=pow3(n);t=pow2(n); for(i=1;i<=m;i++) for(j=i;j<=t;j++) for(k=j;k<=n;k++) { if(i*j*k>n) continue; if(i==j&&j==k) ans++; else if(i<j&&j<k) ans+=6; else ans+=3; } printf("Case %d: %I64d ",++ca,ans); } return 0; }
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cstdlib> #include <cmath> #include <vector> #include <list> #include <deque> #include <queue> #include <iterator> #include <stack> #include <map> #include <set> #include <algorithm> #include <cctype> using namespace std; typedef __int64 LL; const int N=400005; const LL II=1000000007; const int INF=0x3f3f3f3f; const double PI=acos(-1.0); LL pow3(LL n) { LL p=(LL)pow(n,1.0/3); while(p*p*p<=n) p++; while(p*p*p>n) p--; return p; } LL pow2(LL n) { LL p=(LL)pow(n,1.0/2); while(p*p<=n) p++; while(p*p>n) p--; return p; } int main() { LL n; int ca=0; while(~scanf("%I64d",&n)) { LL m,ans=0,i,j; m=pow3(n); ans+=m;//第一种,三个相等的情况 for(i=1;i<=m;i++) { LL t=n/i; LL k=pow2(t); ans+=(t/i+k-i*2)*3;//第二种,前两个相等-后面的比前面的大,或则后两个相同比前面的大 for(j=i+1;j<=k;j++) ans+=(t/j-j)*6;//第三种,都不相等从小到大 } printf("Case %d: %I64d ",++ca,ans); } return 0; }