BZOJ 2671 Calc 数论

42 篇文章 0 订阅

题目大意:给定 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 <script type="math/tex" id="MathJax-Element-125">b</script>的约数搞一搞就好了
复杂度是啥?
别管了暴力出奇迹就是了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#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*i<n;i++)
        if(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;a<b&&b*(a+b)<=n;a=last+1)
        {
            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<<Calculate()<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值