Simple Math Problem
-
这个是一个数论题目,我们先将题目要求的式子进行转化
∑ i = 1 n ∑ j = 1 i [ g c d ( i , j ) = = 1 ] f [ j ] = ∑ i = 1 n ∑ j = 1 n f [ i ] [ g c d ( i , j ) = 1 ] − ∑ i = 1 n ∑ j = 1 i f [ i ] [ g c d ( i , j ) = 1 ] + f ( 1 ) \sum_{i=1}^n\sum_{j=1}^i[gcd(i,j)==1]f[j] \\ =\sum_{i=1}^n\sum_{j=1}^nf[i][gcd(i,j)=1]-\sum_{i=1}^n\sum_{j=1}^if[i][gcd(i,j)=1]+f(1) i=1∑nj=1∑i[gcd(i,j)==1]f[j]=i=1∑nj=1∑nf[i][gcd(i,j)=1]−i=1∑nj=1∑if[i][gcd(i,j)=1]+f(1) -
这个式子可以这样理解,我们需要枚举从1-n的所有的数字,然后找到比这个数字i小的j,同时满足i和j互质,将f(j)的贡献累加到答案(也就是对于每对互质的元组,我们只计算小的那个数字的贡献)。其实就是先求出枚举1-n的所有的数字i,然后计算与i互质的数字的个数,将f(i)的每个贡献累加在一起。注意这里的互质的元组(i,j)不一定是i更大的,存在i>j和i<j的情况。求出这个之后,我们只需要减去从1-n进行枚举i,然后求出对于每个i,小于i的同时与i互质的数字的个数,然后累加f(i)的贡献。这样其实就是对于每个元组(i,j),这里的i是大于j的。减去之后剩下的就是对于每对互质的元组,这里的满足i<j,同时计算小的那个数字的贡献。这样不就是我们所求的吗?但是最后计算的时候发现总是会比正确的答案少1,这是因为(1,1)这个位置是特殊的,没有计算到,所以我们最后还要加上1就行了。
-
计算的话,式子的前半部分利用莫比乌斯反演进行求解。后半部分就是一个欧拉函数求解即可。
-
代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
ll f[N],phi[N],mu[N];
bool vis[N];
ll prime[N],g[N];
int m=0;
int n;
// 获取f数组
int getsum(int x){
int sum=0;
while(x){
sum+=(x%10);
x/=10;
}
return sum;
}
// 得到莫比乌斯函数和欧拉函数
void getmu(){
phi[1]=1,mu[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
mu[i]=-1;
phi[i]=i-1;
prime[++m]=i;
}
for(int j=1;j<=m&&(ll)i*prime[j]<=n;j++){
vis[i*prime[j]]=true;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
mu[i*prime[j]]=0;
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
mu[i*prime[j]]=-mu[i];
}
}
// 求一个前缀和,求每个数倍数的f数组的总和
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j+=i){
g[i]+=f[j];
}
}
}
int main(){
memset(vis,false,sizeof(vis));
cin>>n;
for(int i=1;i<=n;i++){
f[i]=getsum(i);
}
getmu();
ll ans1=0,ans2=0;
for(int i=1;i<=n;i++){
ans1+=mu[i]*(n/i)*g[i];
ans2+=f[i]*phi[i];