NOI2016 循环之美

题目传送门

分析:
反正都是看博客写的,直接上链接,写得很好
OrzOrzOrz

这题可以用来复习一下杜教筛
列两个公式记一下:

(F(n)=sum_{i=1}^{n}mu(i)=1-sum_{i=2}^{n}F(lfloorfrac{n}{i} floor))
(G(n)=sum_{i=1}^{n}varphi(i)=frac{n(n+1)}{2}-sum_{i=2}^{n}G(lfloorfrac{n}{i} floor))
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<ctime>
#include<set>

#define maxn 200005

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m,K;
long long pri[maxn],mu[maxn],cnt;
int np[maxn],prik[maxn],cntk;
long long f[2005],ans;
map<long long,long long>Mu;
map<long long,long long>G[11];

inline int gcd(int p,int q)
{return q?gcd(q,p%q):p;}
inline void init()
{
	mu[1]=1;
	for(int i=2;i<maxn;i++)
	{
		if(!np[i])pri[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*pri[j]<maxn;j++)
		{
			np[i*pri[j]]=1;
			if(i%pri[j]==0)break;
			mu[i*pri[j]]=-mu[i];
		}
	}
	for(int i=1;i<maxn;i++)mu[i]+=mu[i-1];
	for(int i=1;i<=K;i++)f[i]=f[i-1]+(gcd(i,K)==1);
}

inline long long getf(int x){return (x/K)*f[K]+f[x%K];}
inline long long getmu(int x)
{
	if(x<maxn)return mu[x];
	if(Mu.count(x))return Mu[x];
	long long tmp=1;
	for(int i=2,j;i<=x;i=j+1)
		j=x/(x/i),tmp-=getmu(x/i)*(j-i+1);
	return Mu[x]=tmp;
}
inline long long getg(int x,int y)
{
	if(!x)return getmu(y);
	if(y<=1)return y;
	if(G[x].count(y))return G[x][y];
	return G[x][y]=getg(x-1,y)+getg(x,y/prik[x]);
}

int main()
{
	n=getint(),m=getint(),K=getint();
	init();
	for(int i=1;i<=cnt&&pri[i]<=K;i++)if(K%pri[i]==0)prik[++cntk]=pri[i];
	for(int i=1,j;i<=min(n,m);i=j+1)
	{
		j=min(n/(n/i),m/(m/i));
		ans+=(getg(cntk,j)-getg(cntk,i-1))*(n/i)*getf(m/i);
	}
	printf("%lld
",ans);
}

原文地址:https://www.cnblogs.com/Darknesses/p/12986518.html