终于下定决心好好搞搞数论了
首先这里的题解法全部故意避开莫比乌斯反演
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