终于下定决心好好搞搞数论了
首先这里的题解法全部故意避开莫比乌斯反演
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; }
这道题。。看了一个小时才看懂
首先我们要得出 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; }