HDU6434 Problem I. Count(欧拉函数)

HDU6434 Problem I. Count(欧拉函数)

题目大意


∑ i = 1 n ∑ j = 1 i − 1 [ g c d ( i − j , i + j ) = 1 ] ( n ≤ 2 e 7 ) \sum_{i=1}^n\sum_{j=1}^{i-1}[gcd(i-j,i+j)=1](n\le 2e7) i=1nj=1i1[gcd(ij,i+j)=1](n2e7)
T( T ≤ 1 e 5 T\le 1e5 T1e5)组数据.

解题思路(误)

莫比乌斯反演

原式可以写作
∑ i = 1 n ∑ j = 1 n − i [ g c d ( i , i + 2 j ) = 1 ] = ∑ i = 1 n ∑ j = 1 n − i ∑ d ∣ i , 2 ∗ j μ [ d ] \begin{aligned} &\sum_{i=1}^n\sum_{j=1}^{n-i}[gcd(i,i+2j)=1]\\ &=\sum_{i=1}^n\sum_{j=1}^{n-i}\sum_{d|i,2*j}\mu[d] \end{aligned} i=1nj=1ni[gcd(i,i+2j)=1]=i=1nj=1nidi,2jμ[d]
由此,只需要通过整除分块即可得出答案

TLE代码

#include
using namespace std;
const int size=2e7+5;
bool prime[size];
int p[size],mu[size];
int summu[size][2];
int tot;
void init()
{
	mu[1]=1;
	for(int i=1;i<size;i++) prime[i]=true;
	for(int i=2;i<size;i++)
	{
		if(prime[i]){p[++tot]=i;mu[i]=-1;} 
		for(int j=1;j<=tot&&p[j]*i<size;j++)
		{
			prime[i*p[j]]=false;
			if(i%p[j]==0)
			{
				mu[i*p[j]]=0;
				break;
			}
			else mu[i*p[j]]=-mu[i];
		}
	}
	summu[0][0]=summu[0][1]=0;
	for(int i=1;i<size;i++)
	{
		summu[i][0]=summu[i-1][0];
		summu[i][1]=summu[i-1][1];
		summu[i][i%2]+=mu[i];
	}
}
int main()
{
	init();
	int t;
	scanf("%d",&t);
	int n;
	while(t--)
	{
		scanf("%d",&n);
		long long ans=0;
		for(int l=1,r;l<=n;l=r+1)
		{
			r=n/(n/l);
			int tp=n/l;
			ans+=(summu[r][1]-summu[l-1][1])*(tp-1)*tp/2;
		}
		for(int l=2,r;l<=n;l=r+1)
		{
			r=2*n/(2*n/l);
			int tp=2*n/l;
			ans+=(summu[r][0]-summu[l-1][0])*(tp-2+tp%2)*(tp/2)/2;
		}
		printf("%lld\n",ans);
	}
}

正确的解题思路

原式可以写作
∑ i = 1 n ∑ j = 1 i − 1 [ g c d ( j , 2 i − j ) = 1 ] \sum_{i=1}^n\sum_{j=1}^{i-1}[gcd(j,2i-j)=1] i=1nj=1i1[gcd(j,2ij)=1]
显然有若j与2i互素,则j与2i-j也会互素,因此有 φ [ 2 i ] / 2 = ∑ j = 1 i − 1 [ g c d ( j , 2 i − j ) = 1 ] \varphi[2i]/2=\sum_{j=1}^{i-1}[gcd(j,2i-j)=1] φ[2i]/2=j=1i1[gcd(j,2ij)=1]

AC代码

#include
using namespace std;
const int size=2e7+5;
bool prime[size];
int p[size],phi[size],tot;
long long ans[size];
void init()
{
	phi[1]=1;
	for(int i=1;i<size;i++) prime[i]=true;
	for(int i=2;i<size;i++)
	{
		if(prime[i])
		{
			p[++tot]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=tot&&p[j]*i<size;j++)
		{
			prime[i*p[j]]=false;
			if(i%p[j]==0)
			{
				phi[i*p[j]]=phi[i]*p[j];
				break;
			}
			else phi[i*p[j]]=phi[i]*phi[p[j]];
		}
	}
	ans[0]=0;
	for(int i=1;i<size;i++)
	{
		long long tmp=phi[i];
		if(i%2==0) tmp*=2;
		ans[i]=ans[i-1]+tmp/2;
	}
}
int main()
{
	int t;
	init();
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		printf("%lld\n",ans[n]);
	}
}
	

你可能感兴趣的:(数论,数学)