hdu4473
这题的结果[f(1)+f(2)+...+f(n)]其实就等价于x*y*z<=n的解的个数,然后的方法几乎就是暴力枚举了。现场比赛的时候没想到这一点,太杯具了,浪费了两个小时的思考时间。其实我们的做法应该是可行的,因为f(n)具有积性性质,也就是若gcd(n, m)=1,则f(n*m)=f(n)*f(m)。而当p为质数时,f(p^k)=(k+1)*(k+2)/2,这样就能把f(n)数列的前n项和化成一堆多项式的加和。然后用合并同类项的思想,用容斥原理搞,可是代码量太大了,没打出来。。。
今天赛题被挂到HDOJ上以后用上面说的枚举方法打了一下,交上去居然WA,调了半天也没发现错误,最后才怀疑是sqrt和pow函数的精度问题,马上查了一下解题报告,果然都是手动写的开平方和开立方函数。加上以后就过了~~
/* * hdu4473/win.cpp * Created on: 2012-11-17 * Author : ben */ #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <iostream> #include <algorithm> #include <queue> #include <set> #include <map> #include <stack> #include <string> #include <vector> #include <deque> #include <list> #include <functional> #include <numeric> #include <cctype> using namespace std; typedef long long LL; inline LL sqrt2(LL n) { LL m = (LL)sqrt(n + 0.0); while(m * m <= n) m++; while(m * m > n) m--; return m; } inline LL sqrt3(LL n) { LL m = (LL) pow(n, 1 / 3.0); while (m * m * m <= n) m++; while (m * m * m > n) m--; return m; } LL work(LL n) { LL ret = 0; LL t1 = sqrt3(n); ret += t1; for(LL a = 1; a <= t1; a++) { ret += 3 * (n / (a * a) - a); ret += 3 * (sqrt2(n / a) - a); LL t2 = sqrt2(n / a); for(LL b = a + 1; b <= t2; b++) { ret += 6 * (n / (a * b) - b); } } return ret; } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif int t = 1; LL n; while(scanf("%I64d", &n) == 1) { printf("Case %d: %I64d\n", t++, work(n)); } return 0; }