关于数论

终于下定决心好好搞搞数论了

首先这里的题解法全部故意避开莫比乌斯反演

bzoj2810:

入门级,先线筛欧拉

sum[1]=1;
	for(ll i=1;i<=n;i++)phi[i]=i;
	for(ll i=2;i<=n;i++){
		if(phi[i]==i){
			for(ll j=i;j<=n;j+=i){
				phi[j]=phi[j]/i*(i-1);
			}
		}
		sum[i]=sum[i-1]+phi[i];
	}
然后有一个结论:

求gcd(i,j)=x 1<=i,j<=n 的对数等于求gcd(i,j)=1 1<=i,j<=n/x的对数

对欧拉函数求前缀和,枚举;

//Copyright(c)2015 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
inline void splay(ll &v){
	v=0;char c=0;ll p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
ll phi[10000010];
ll sum[10000010];
ll ans;
ll get(ll num){
	return (sum[num]<<1)-1;
}
int main(){
	freopen("xxx.in","r",stdin);
	freopen("xxx.out","w",stdout);
	ll n;splay(n);sum[1]=1;
	for(ll i=1;i<=n;i++)phi[i]=i;
	for(ll i=2;i<=n;i++){
		if(phi[i]==i){
			for(ll j=i;j<=n;j+=i){
				phi[j]=phi[j]/i*(i-1);
			}
		}
		sum[i]=sum[i-1]+phi[i];
	}
	for(ll i=2;i<=n;i++){
		if(phi[i]==i-1){
			ans+=get(n/i);
		}
	}
	cout<<ans<<endl;
}

bzoj 2190

同理 对欧拉函数求前缀和,枚举;

答案:sigma(phi[i])*2-1+2 (i<n)

//Copyright(c)2015 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
inline void splay(ll &v){
	v=0;char c=0;ll p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
ll phi[10000010];
ll sum[10000010];
ll ans;
int main(){
	freopen("xxx.in","r",stdin);
	freopen("xxx.out","w",stdout);
	ll n;splay(n);sum[1]=1;
	for(ll i=1;i<=n;i++)phi[i]=i;
	for(ll i=2;i<=n;i++){
		if(phi[i]==i){
			for(ll j=i;j<=n;j+=i){
				phi[j]=phi[j]/i*(i-1);
			}
		}
		sum[i]=sum[i-1]+phi[i];
	}
	for(ll i=1;i<n;i++){
		ans+=phi[i];
	}
	cout<<ans*2+1<<endl;
}

bzoj 2005

这道题。。看了一个小时才看懂

首先我们要得出 f[i]为gcd(x,y)=i的对数

那么我们可以发现 f[i]=取下整(n/i)*(m/i)-f[i*2]-f[i*3]-f[i*4].....

那么倒着求f[i]就好了

我卡在了最后统计方案数上

对于每一个数对(x,y),令gcd(x,y)==t

那么它会对答案产生(i-1)*2+1的贡献

为什么?我们想想gcd的意义:从(0,0)开始走向(x,y)所经过的整点数-1

那么根据题意我们可以发现贡献为(i-1)*2+1

//Copyright(c)2015 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
ll f[100010];
ll n,m;
int main(){
	freopen("xxx.in","r",stdin);
	freopen("xxx.out","w",stdout);
	cin>>n>>m;ll ans=0;
	for(ll i=min(n,m);i>=1;i--){
		f[i]=(n/i)*(m/i);
		for(ll j=i<<1;j<=min(n,m);j+=i)f[i]-=f[j];
		ans+=(f[i]*(2*i-1));
	}
	cout<<ans<<endl;
}

bzoj

你可能感兴趣的:(关于数论)