P2158 [SDOI2008]仪仗队(欧拉函数&莫反)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2158 [SDOI2008]仪仗队(欧拉函数&莫反)相关的知识,希望对你有一定的参考价值。

P2158 [SDOI2008]仪仗队(欧拉函数&莫反)

考虑不同的斜率个数,则求 ∑ i = 1 n ∑ i = 1 n [ g c d ( i , j ) = 1 ] \\sum\\limits_{i=1}^n\\sum\\limits_{i=1}^n [gcd(i,j)=1] i=1ni=1n[gcd(i,j)=1]

转换一下: ∑ i = 1 n ∑ i = 1 n [ g c d ( i , j ) = 1 ] \\sum\\limits_{i=1}^n\\sum\\limits_{i=1}^n [gcd(i,j)=1] i=1ni=1n[gcd(i,j)=1]

φ ( i ) = ∑ j = 1 i [ g c d ( i , j ) = 1 ] \\varphi(i)=\\sum\\limits_{j=1}^i[gcd(i,j)=1] φ(i)=j=1i[gcd(i,j)=1]

∑ i = 1 n ∑ i = 1 n [ g c d ( i , j ) = 1 ] = 2 ∑ i = 1 n φ ( i ) − 1 \\sum\\limits_{i=1}^n\\sum\\limits_{i=1}^n [gcd(i,j)=1]=2\\sum\\limits_{i=1}^n\\varphi(i)-1 i=1ni=1n[gcd(i,j)=1]=2i=1nφ(i)1

为了方便出来,先用对角线分割。

计算出 ∑ i = 1 n − 1 ∑ i = 1 n − 1 [ g c d ( i , j ) = 1 ] \\sum\\limits_{i=1}^{n-1}\\sum\\limits_{i=1}^{n-1} [gcd(i,j)=1] i=1n1i=1n1[gcd(i,j)=1]

然后加上2。

就是答案了。

时间复杂度: O ( n ) O(n) O(n)

code

// Problem: P2158 [SDOI2008]仪仗队
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2158
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-07 09:58:29
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=4e4+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
bitset<N>vis;
int p[N],cnt;
int phi[N];
void ss(int n){
	phi[1]=vis[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) p[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt&&i*p[j]<=n;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];
				break;
			}
			phi[i*p[j]]=phi[i]*phi[p[j]];
		}
	}
}
int main(){
	int n;
	scanf("%d",&n);
	ss(n);
	ll s=0;
	for(int i=1;i<n;i++) s+=phi[i];
	printf("%lld\\n",n==1?0:(s<<1)+1);
	return 0;
}

本题还可以用莫反搞一下。

在这里插入图片描述

利用性质: ∑ d ∣ n μ ( d ) = [ n = 1 ] \\sum\\limits_{d|n}\\mu(d)=[n=1] dnμ(d)=[n=1]

在本题就是这个形式: ∑ d μ ( d ) ( n d ) 2 \\sum\\limits_{d}\\mu(d)(\\dfrac{n}{d})^2 dμ(d)(dn)2

预处理一波前缀和,然后整出分块就秒了。

不过时间复杂度还是 O ( n ) O(n) O(n)的。

code

// Problem: P2158 [SDOI2008]仪仗队
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2158
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-07 09:58:29
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=4e4+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
bitset<N>vis;
int p[N],cnt;
int mu[N];
void ss(int n){
	mu[1]=vis[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]) p[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*p[j]<=n;j++){
			vis[i*p[j]]=1;
			if(i%p[j]==0){
				mu[i*p[j]]=0;
				break;
			}
			mu[i*p[j]]=mu[i]*mu[p[j]];
		}
	}
	for(int i=1;i<=n;i++) mu[i]+=mu[i-1];
}
int main(){
	int n;
	scanf("%d",&n);
	ss(n);
	ll s=0;
	n--;
	for(int l=1,r;l<=n;l=r+1){
		r=n/(n/l);
		int d=n/l;
		s+=1LL*(mu[r]-mu[l-1])*d*d;
	}
	printf("%lld\\n",!n?0:s+2);
	return 0;
}

貌似还可以杜教筛?不会qwq

以上是关于P2158 [SDOI2008]仪仗队(欧拉函数&莫反)的主要内容,如果未能解决你的问题,请参考以下文章

P2158 [SDOI2008] 仪仗队(欧拉函数模板)

P2158 [SDOI2008]仪仗队

P2158 [SDOI2008]仪仗队

[洛谷P2158] [SDOI2008]仪仗队

解题报告_算法题单_索引

P2158 [SDOI2008]仪仗队