HDU5382 GCD?LCM!

description

Let's define

\[F(n)=\sum_{i=1}^n\sum_{j=1}^n[\text{lcm}(i,j)+\gcd(i,j)\ge n]\\ S(n)=\sum_{i=1}^nF(i) \]

Find S(n)\(\bmod 258280327\)

data range

\(T\le 10^5,n\le 10^6\)

solution

It's obvious that if we can calculate \(F(n)\) quickly, the problem is solved.

How to calculate \(F(n)\)?Let's define \(G(n)\) as follows:

\[G(n)=\sum_{i=1}^n\sum_{j=1}^n[\text{lcm}(i,j)+\gcd(i,j)= n] \]

then

\[F(n)=F(n-1)+2n-1-G(n-1) \]

Now the key point is to calculate \(G(n)\) quickly.

\[G(n)=\sum_{i=1}^n\sum_{j=1}^n[\text{lcm}(i,j)+\gcd(i,j)= n]\\ =\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^n[\frac{ij}d+d=n][\gcd(i,j)=d]\\ =\sum_{d=1}^n\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac nd}[ijd+d=n][\gcd(i,j)=1]\\ =\sum_{d=1}^n\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac nd}[ij=\frac nd-1][\gcd(i,j)=1] \]

Let's define

\[t(n)=\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=1][ij=n] \]

then

\[G(n)=\sum_{d=1}^nt(\frac nd-1)=\sum_{d\mid n}^nt(\frac nd-1) \]

To my surprise, \(t(n)\) is easy to calculate. In fact, \(t(n)=2^k\),in which \(k\) means the number of different prime factors in \(n\), because to make sure the condition \(\gcd(i,j)=1\) ,prime factors of the same kind should be assigned to either \(i\) or \(j\), which are only \(2\) ways, so for \(k\) different types of prime factors there are \(2^k\) ways .We can use linear sieve to find \(t(n)\) .Then, we can find \(G(n)\) through enumerating the multiples. After that, the problem is solved successfully .

time complexity

\(\mathcal O(n\ln n)\)

code

#include<cstdio>
using namespace std;
const int N=1e6+5,mod=258280327;
bool flag[N];int pr[N],pcnt,t[N],g[N],f[N];
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline void pre()
{
	t[1]=1;int n=N-5;
	for(int i=2;i<=n;++i)
	{
		if(!flag[i])pr[++pcnt]=i,t[i]=2;
		for(int j=1;j<=pcnt;++j)
		{
			int num=i*pr[j];if(num>n)break;
			flag[num]=1;
			if(i%pr[j])t[num]=add(t[i],t[i]);
			else{t[num]=t[i];break;}
		}
	}
	for(int i=1;i<=n;++i)
		for(int j=i;j<=n;j+=i)
			g[j]=add(g[j],t[j/i-1]);
	for(int i=1;i<=n;++i)
		f[i]=add(f[i-1],dec(2*i-1,g[i-1]));
	for(int i=1;i<=n;++i)f[i]=add(f[i],f[i-1]);
}
int main()
{
	pre();int T,n;scanf("%d",&T);
	while(T-->0)scanf("%d",&n),printf("%d\n",f[n]);
	return 0;
}

inspiration

It's of vital importance to consider combinatorial meaning while deduction .

posted @ 2021-02-13 11:09  BILL666  阅读(78)  评论(0编辑  收藏  举报