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;
 } 

T了一个点

这是我想了一个牛(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)。

posted @ 2022-05-08 09:26  starrylasky  阅读(25)  评论(0)    收藏  举报