/** 题目:hdu6134 Battlestation Operational 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6134 题意:f(n) = sigma[1<=i<=n]sigma[1<=j<=i]ceil[i/j] (gcd(i,j)==1) 给定一个n,求f(n); 思路: 公式: n = sigma[d|n]phi[d] = sigma[d|n]phi[n/d]; phi[x]表示<=x的数与x互质的个数。 证明: gcd(i,n)==d => gcd(i/d,n/d)=1; 那么和n最大公约数为d的个数为phi[n/d]; 所以n = sigma[d|n]phi[n/d] = sigma[d|n]phi[d]; 根据n = sigma[d|n]phi[d]; 那么有定义: h(i)表示sigma[1<=j<=i]ceil[i/j] (gcd(i,j)==1) 这里的j都是和i互质时候计算的结果。 g(i)表示sigma[1<=j<=i]ceil[i/j] 那么h(i) = sigma[d|i]mu[d]*g(i/d); 计算所有的g(d)(1<=d<=n)通过枚举j跳在d中跳的方式处理出来,然后前缀和(也可以直接计算出来。不需要再求前缀和,具体看代码) 计算出来所有的h(i)。f(i) = sigma[1<=j<=i]h(j); */ #include<bits/stdc++.h> #define LL long long using namespace std; const int N = 1e6+10; const int mod = 1e9 + 7; LL f[N], g[N], h[N]; int prime[N], tot, not_prime[N]; int mu[N]; void mobius() { mu[1] = 1; tot = 0; for(int i = 2; i < N; i++){ if(!not_prime[i]){ prime[++tot] = i; mu[i] = -1; } for(int j = 1; prime[j]*i<N; j++){ not_prime[prime[j]*i] = 1; if(i%prime[j]==0){ mu[prime[j]*i] = 0; break; } mu[prime[j]*i] = -mu[i]; } } } void init() { for(int i = 1; i < N; i++){ g[i]++; for(int j = i+1; j < N; j+=i){ g[j]++; } } for(int i = 1; i < N; i++) g[i] = (g[i]+g[i-1])%mod; for(int i = 1; i < N; i++){ for(int j = i; j < N; j+=i){ h[j] = (h[j]+mu[i]*g[j/i]%mod+mod)%mod; } } for(int i = 1; i < N; i++){ f[i] = (f[i-1]+h[i])%mod; } } int main() { int n; mobius(); init(); while(scanf("%d",&n)==1) { printf("%lld\n",f[n]); } return 0; }
时间: 2024-12-07 09:54:50