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=1∑ni=1∑n[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=1∑ni=1∑n[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=1∑i[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=1∑ni=1∑n[gcd(i,j)=1]=2i=1∑nφ(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=1∑n−1i=1∑n−1[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] d∣n∑μ(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]仪仗队(欧拉函数&莫反)的主要内容,如果未能解决你的问题,请参考以下文章