zoukankan      html  css  js  c++  java
  • 【BZOJ 2671】 2671: Calc (数论,莫比乌斯反演)

    2671: Calc

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 303  Solved: 157

    Description

      给出N,统计满足下面条件的数对(a,b)的个数:
      1.1<=a<b<=N
      2.a+b整除a*b

    Input

     一行一个数N

    Output

     一行一个数表示答案

    Sample Input

    15

    Sample Output

    4

    HINT

    数据规模和约定

    Test N Test N 

    1 <=10 11 <=5*10^7 

    2 <=50 12 <=10^8 

    3 <=10^3 13 <=2*10^8 

    4 <=5*10^3 14 <=3*10^8 

    5 <=2*10^4 15 <=5*10^8 

    6 <=2*10^5 16 <=10^9 

    7 <=2*10^6 17 <=10^9 

    8 <=10^7 18 <=2^31-1 

    9 <=2*10^7 19 <=2^31-1 

    10 <=3*10^7 20 <=2^31-1

    Source

    【分析】

      这题的复杂度还挺迷人的。

      然后$sqrt n$也没发现,以为筛$mu$都要$O(n)$,什么杜教筛的幸好不会。。

      首先分析$(a+b)|(a*b) → (a/g+b/g)|(a/g*b/g*g) →(a/g+b/g)|g$

      那就是互质的$a',b'$ 找他们的公倍数$g$就行了。

      写正常一点就是$$sum_{j=1}^{N}sum_{i=1}^{j-1}dfrac{n}{j*(i+j)} [gcd(i,j)==1]$$

      到了这里,我就傻眼了,其实嘛。。。j并不会到$n$,只是到$sqrt{n}$

      $$sum_{j=1}^{sqrt{n}}sum_{i=1}^{j-1}dfrac{n}{j*(i+j)} [gcd(i,j)==1]$$

      然后我又傻眼了,复杂度迷人的东西啊会把我脑子弄得很乱的。

      直接枚举j,然后i那里分块,然后就是求[l,r]里面和j互质的数的个数。

      差分,先求[1,r]里面的,就是$sum_{x=1}^{r}1[gcd(x,j)==1]$

      即$sum_{d=1}^{r}mu(d)*(r/d)$

      最后就是$sum_{d=1}^{r}mu(d)*(r/d-(l-1)/d)$

      枚举约数在前面$sqrt{j}$枚举去了。。

      真的是暴力出奇迹了。。。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<cmath>
     7 using namespace std;
     8 #define Maxn 50010
     9 #define LL long long
    10 
    11 bool vis[Maxn];
    12 int pri[Maxn],pl,mu[Maxn];
    13 
    14 int mymin(int x,int y) {return x<y?x:y;}
    15 
    16 void init()
    17 {
    18     memset(vis,0,sizeof(vis));
    19     pl=0;mu[1]=1;
    20     for(int i=2;i<=Maxn;i++)
    21     {
    22         if(!vis[i]) pri[++pl]=i,vis[i]=1,mu[i]=-1;
    23         for(int j=1;j<=pl;j++)
    24         {
    25             if(i*pri[j]>Maxn) break;
    26             vis[i*pri[j]]=1;
    27             if(i%pri[j]==0) {mu[i*pri[j]]=0;break;}
    28             mu[i*pri[j]]=-mu[i];
    29         }
    30     }
    31 }
    32 
    33 int sta[Maxn],sl;
    34 
    35 void div(int x)
    36 {
    37     sl=0;
    38     int i;
    39     for(i=1;i*i<x;i++)
    40     {
    41         if(x%i==0) sta[++sl]=i,sta[++sl]=x/i;
    42     }
    43     if(i*i==x) sta[++sl]=i;
    44 }
    45 
    46 int gcd(int a,int b)
    47 {
    48     if(b==0) return a;
    49     return gcd(b,a%b);
    50 }
    51 
    52 int main()
    53 {
    54     int n;
    55     scanf("%d",&n);
    56     init();
    57     LL ans=0;
    58     int sq=(int)(sqrt((double)n));
    59     for(int i=1;i<=sq;i++)
    60     {
    61         div(i);
    62         for(int j=1;j<i;)
    63         {
    64             int x=n/i/(i+j),r;if(x==0) break;
    65             r=mymin(i-1,n/x/i-i);
    66             for(int k=1;k<=sl;k++)
    67             {
    68                 ans+=mu[sta[k]]*(r/sta[k]-(j-1)/sta[k])*x;
    69             }
    70             j=r+1;
    71         }
    72     }
    73     printf("%lld
    ",ans);
    74     return 0;
    75 }
    View Code

    2017-04-06 15:50:26

  • 相关阅读:
    基于RSA的WEB前端密码加密方案
    私钥加密公钥解密或者公钥加密私钥解密有意义吗?
    MySQL索引背后的数据结构及算法原理
    深入理解MySQL索引原理和实现——为什么索引可以加速查询?
    shim和polyfill有什么区别
    [转]使用HttpOnly提升Cookie安全性
    RLE压缩算法详解
    [转]详解布隆过滤器的原理,使用场景和注意事项
    小白科普:Netty有什么用?
    RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密?
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6673837.html
Copyright © 2011-2022 走看看