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;
}
原文地址:https://www.cnblogs.com/moonbay/p/2766607.html