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;

}

你可能感兴趣的:(HDU)