BZOJ 2671 Calc 数论

题目大意:给定 N ,求 ni=1nj=1[i+j|ij]1
跪Nodgd= =
不妨设 d=gcd(i,j),i=ad,j=bd,gcd(a,b)=1 ,那么有
(a+b)d|abd2

a+b|abd
gcd(a,b)=1
gcd(a+b,a)=1,gcd(a+b,b)=1
a+b|d
不妨设 d=(a+b)t ,那么我们求的就是三元组 (a,b,t) 的个数,其中满足 a<b,gcd(a,b)=1,b(a+b)tN

那么如果我们的 a b 确定了,满足要求的 t 显然有 Nb(a+b)
由于 bN1 ,我们不妨枚举 b
那么有
ans=N1b=1b1a=1[gcd(a,b)=1]Nb(a+b)
对于一个确定的 b Nb(a+b) 最多只有 2N 个取值,我们可以分段处理
对于一段 [lower,upper] ,我们需要求出这一段中与 b 互质的数的个数
由容斥原理易知这样的数有 k|bμ(k)(upperklower1k) 个,枚举 b 的约数搞一搞就好了
复杂度是啥?
别管了暴力出奇迹就是了

#include 
#include 
#include 
#include 
#define M 50500
using namespace std;

long long n;

long long stack[M],top;

int mu[M],prime[M],tot;
bool not_prime[M];
void Linear_Shaker()
{
    int i,j;
    mu[1]=1;
    for(i=2;i<=50000;i++)
    {
        if(!not_prime[i])
        {
            prime[++tot]=i;
            mu[i]=-1;
        }
        for(j=1;prime[j]*i<=50000;j++)
        {
            not_prime[prime[j]*i]=true;
            if(i%prime[j]==0)
            {
                mu[prime[j]*i]=0;
                break;
            }
            mu[prime[j]*i]=-mu[i];
        }
    }
}
void Get_Divisor(long long n)
{
    long long i;
    top=0;
    for(i=1;i*iif(n%i==0)
            stack[++top]=i,stack[++top]=n/i;
    if(i*i==n)
        stack[++top]=i;
    sort(stack+1,stack+top+1);
}
long long Calculate()
{
    long long a,b,k,last,re=0;
    for(b=1;b*(b+1)<=n;b++)
    {
        Get_Divisor(b);
        for(a=1;a1)
        {
            last=min(n/(n/b/(a+b))/b-b,b-1);
            long long cnt=0;
            for(k=1;stack[k]<=last;k++)
                cnt+=mu[stack[k]]*(last/stack[k]-(a-1)/stack[k]);
            re+=n/b/(a+b)*cnt;
        }
    }
    return re;
}
int main()
{
    cin>>n;
    Linear_Shaker();
    cout<

你可能感兴趣的:(数论,BZOJ)