Post

P6583回首过去

P6538回首过去

题意:
求出有序整数对 $(x,y)$ 的个数,满足 $1\le x,y\le n$ 且 $\frac{x}{y}$ 可以表示为十进制有限小数。

  • Subtask 1(40 分),$1 \le n \le 10^3$;
  • Subtask 2(40 分),$1 \le n \le 10^7$;
  • Subtask 3(20 分),$1 \le n \le 10^{12}$。
    思路:
    10进制小数必然可以写成 $\frac{a}{1000…}$ 的形式,即分母为 $10^{x}$ ,即 $2^{x} \cdot 5^{x}$

    做法一

    枚举x,y为 $N^2$,约分gcd为 $logN$,判断分母 $logN$
    复杂度:$O(N^2logN)$

    做法二

    把分数分解可以写成以下形式: $ \frac{bc}{ac} $
    其中a只含2和5的因子,c为不包含2和5的因子,b的范围为 $[1,\lfloor \frac{n}{c} \rfloor]$
    a可以预处理出来,枚举a值,再枚举c值,每次加上 $\lfloor \frac{n}{c} \rfloor$(即b的个数),分母[1,n]都被枚举了一遍
    复杂度: $O(N)$

    做法三

    发现答案会加上很多个 $ \lfloor \frac{n}{c} \rfloor $,考虑整除分块 性质: $a \cdot c$ 最大值范围限定为n,即随着c的增大,a的最大值会减小
    此时先枚举c的值,这样b还是 $[1, \lfloor \frac{n}{c} \rfloor ]$的任意数,a限定在 $[1, \lfloor \frac{n}{c} \rfloor ]$范围内,因此可以每次减少a的最大值使其小于 $\lfloor \frac{n}{c} \rfloor$,可以用一个数来维护a能满足的个数,c的范围内不能被2和5整除的个数可以利用类似前缀和的方法算出
    定义 $g(l,r,x)$ 表示l,r内被x整除的个数
    则c的个数为 $g(l,r,1)-g(l,r,2)-g(l,r,5)+g(l,r,10)$
    每次将答案进行累加即可
    复杂度: $O(\sqrt{N})$

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    signed main(){
      cin.tie(0)->sync_with_stdio(0);
      ll n;
      vector<ll> a;
      cin>>n;
      for(ll i=1;i<=n;i*=2){
          for(ll j=i;j<=n;j*=5)a.push_back(j);
      }
      sort(a.begin(),a.end());
      int cnt=a.size()-1;
      ll ans=0;
      for(ll l=1,r;l<=n;l=r+1){
          ll x=n/l;
          //r=(x==0?n:n/x);
          r=n/x;
          while(cnt&&a[cnt]>x)cnt--;
          ll v=r-l+1;
          v-=r/2-(l-1)/2;
          v-=r/5-(l-1)/5;
          v+=r/10-(l-1)/10;
          ans+=v*(cnt+1)*x;
      }
      cout<<ans<<"\n";
      return 0;
    }
    
This post is licensed under CC BY 4.0 by the author.