bzoj2671 Calc 数论

      太神了。完全不会。。o(╯□╰)o。

      首先来看一下怎样的ab满足条件:

      设d=gcd(a,b),a=du,b=dv,那么:

      a+b|ab → du+dv|d^2uv → u+v|duv,由gcd(u,v)=1 → gcd(u,v,uv)=1 → u+v|d。因此,在本题中就是要找到有多少对u,v,t,其中d=t(u+v),满足:

      b=dv=tv(u+v)<=n,如果枚举u,v答案即ΣuΣv[n/v(u+v)]*[gcd(u,v)=1]。

      显然v(u+v)<=n→v(v+1)<=n,因此我们知道v

      Σ(k|v) μ(k)(y/k-(x-1)/k)(这里/表示整除)

     于是就做完了。。但是如果将一个数的约数个数看做O(N^0.5)的话,时间复杂度为O(N^0.5*(N^0.5)^0.5*(N^0.5)^0.5)=O(N)!所以只能说约数的个数远远不足O(N^0.5)而且分区间的常数也是远远小于1的。。。关键这个算法跑2^31-1半秒都不到!!。

AC代码如下:

#include
#include
#include
#include
#define ll long long
using namespace std;

int n,cnt,tot,c[50005],a[50005],mu[50005]; bool bo[50005];
void pfs(){
	int i,j; memset(bo,1,sizeof(bo)); mu[1]=1;
	for (i=2; i<=50000; i++){
		if (bo[i]){ c[++cnt]=i; mu[i]=-1; }
		for (j=1; j<=cnt && i<=50000/c[j]; j++){
			bo[i*c[j]]=0;
			if (i%c[j]) mu[i*c[j]]=-mu[i]; else{
				mu[i*c[j]]=0; break;
			}
		}
	}
}
void dvs(int x){
	int i; tot=0;
	for (i=1; i*i

by lych

2016.2.4

你可能感兴趣的:(bzoj)