hdu5528

定义\(f(n)=\)选两个\([0,n)\)的整数\(a,b\),且\(ab\)不是\(n\)的倍数的方案数。

\(g(n) = \sum_{d|n}f(d)\)

\(T\leq20000,n\leq10^9\)

解答如下:\((a,b)\)\(gcd(a,b)\)

\[f(n) = n^2-\sum_a\sum_b[n|ab]\\=n^2-\sum_a\sum_b[\frac{n}{(a,n)}|b]\\=n^2-\sum_a\sum_b[\frac{n}{a}|b]\sum_d[d=(a,n)]\\=n^2-\sum_a\sum_d[d=(a,n)]\sum_b[\frac{n}{d}|b]\\=n^2-\sum_{d|n}\sum^{n/d}_{a=1}[1=(a,\frac{n}{d})]\sum_b[\frac{n}{d}|b]\\=n^2-\sum_{d|n}\sum^{n/d}_{a=1}[1=(a,\frac{n}{d})]\sum_b[\frac{n}{d}|b]\\=n^2-\sum_{d|n}\varphi(\frac{n}{d})\sum_b[\frac{n}{d}|b]\\=n^2-\sum_{d|n}\varphi(d)\sum_b{[d|b]}\\=n^2-\sum_{d|n}\varphi(d)\frac{n}{d}\\g(n)=\sum_{d|n}f(d)\\=\sum_{d|n}d^2-\sum_{d|n}\sum_{k|d}\varphi(k)\frac{d}{k} \]

前式很简单,后式是\(\varphi * id * 1=id*id\)

两个值均为积性函数,预处理素因子,合并答案即可

#define B cout << "BreakPoint" << endl;
#define O(x) cout << #x << " " << x << endl;
#define O_(x) cout << #x << " " << x << " ";
#define Msz(x) cout << "Sizeof " << #x << " " << sizeof(x)/1024/1024 << " MB" << endl;
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#define LL long long
const LL inf = 1e9 + 9;
const int N = 1e6 + 5;
using namespace std;
inline LL read() {
	LL s = 0,w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-')
			w = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * w;
}
inline void write( LL x ) {
    if( x >= 10 ) write( x / 10 );
    putchar( x % 10 + '0' );
}
int T;
LL n;
int p[N],vis[N],tot;
void init() {
    vis[1] = 1;
    for(int i = 2; i <= 1e6; ++i) {
        if(!vis[i]) p[++tot] = i;
        for(int j = 1; j <= tot && p[j] * i <= 1e6; ++j) {
            vis[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}
LL solve(LL n) {
    LL ans = 1, num = 1, tn = n;
    for(int i = 1; i <= tot && p[i] * p[i] <= n; ++i) if(n % p[i] == 0){
        LL t = p[i], tmp1 = 1, tmp2 = 0;
        while(n % t==0) {
            n /= t;
            tmp1 = tmp1 * t * t + 1;
            ++tmp2;
        }
        ans *= tmp1;
        num *= (tmp2 + 1);
    }
    if(n != 1) {
        num *= 2;
        ans *= (1 + n * n);
    }
    ans -= num * tn;
    return ans;
}
int main() {
    T = read();
    init();
    while(T--) {
        n = read();
        write(solve(n)); putchar('\n');
    }
    return 0;
}
posted @ 2020-03-15 21:30  优秀的渣渣禹  阅读(102)  评论(0编辑  收藏  举报