P1891题解
P1891 疯狂的lcm
数论题免不了要推式子
\(\sum_{i=1}^n lcm(i,n)\)
\(\sum_{i=1}^n \frac{i*n}{gcd(i,n)}\)
\(n\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}i\)
\(n\sum_{d|n}\sum_{i=1}^d i~[gcd(i,d)==1]\)
\(\sum_{i=1}^di[gcd(i,d)=1]=\frac{\varphi(d)}{2}d\)
\(ans=n\sum_{d|n}\frac{\varphi(d)}{2}d\)
到了这里我就开心的打代码:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N = 1e6;
int n,cnt;
int pre[N+5];
long long pai[N+5];
bool vis[N+5];
inline void before()
{
pai[1]=2;vis[1]=true;
for(re int i=2;i<=N;++i)
{
if(!vis[i]) pre[cnt++]=i,pai[i]=i-1;
for(re int j=0;j<cnt&&pre[j]*i<N;++j)
{
vis[i*pre[j]]=true;
if(i%pre[j]==0)
{
pai[pre[j]*i]=pai[i]*pre[j]; break;
}
pai[i*pre[j]]=pai[i]*pai[pre[j]];
}
}
}
signed main()
{
ios::sync_with_stdio(false);
int T;cin>>T;before();
while(T--)
{
cin>>n;
long long ans=0;
for(re int i=1;i*i<=n;++i)
{
if(n%i==0)
{
ans=(ans+pai[i]*i/2);
if(i*i!=n)
{
int tmp=n/i;
ans=(ans+pai[tmp]*tmp/2);
}
}
}
cout<<ans*n<<endl;
}
return 0;
}
这是我想了一个牛(xiao)逼(la)王(ji)优化。
在n为奇数时i两个两个跳。
上代码:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N = 1e6;
int n,cnt;
int pre[N+5];
long long pai[N+5];
bool vis[N+5];
inline void before()
{
pai[1]=2;vis[1]=true;
for(re int i=2;i<=N;++i)
{
if(!vis[i]) pre[cnt++]=i,pai[i]=i-1;
for(re int j=0;j<cnt&&pre[j]*i<N;++j)
{
vis[i*pre[j]]=true;
if(i%pre[j]==0)
{
pai[pre[j]*i]=pai[i]*pre[j]; break;
}
pai[i*pre[j]]=pai[i]*pai[pre[j]];
}
}
}
signed main()
{
ios::sync_with_stdio(false);
int T;cin>>T;before();
while(T--)
{
cin>>n;
long long ans=0;int e=n&1;
for(re int i=1;i*i<=n;++i)
{
if(n%i==0)
{
ans=(ans+pai[i]*i/2);
if(i*i!=n)
{
int tmp=n/i;
ans=(ans+pai[tmp]*tmp/2);
}
}
if(e==1) ++i;
}
cout<<ans*n<<endl;
}
return 0;
}
别忘了吸口氧(xixi)。

浙公网安备 33010602011771号