zoukankan      html  css  js  c++  java
  • 【数学 技巧】divisor

    没考虑重复lcm处理被卡TLE没A真是可惜

    题目大意

    $n$为$k-可表达的$当且仅当数$n$能被表示成$n$的$k$个因子之和,其中$k$个因子允许相等。

    求$[A,B]$之间$k-可表达$的数的个数

    $T le 5*10^4,2 le K le 7,1 le A le B le 10^{18}$


    题目分析

    每一种拆分可以视作$1=frac{1}{a}+frac{1}{b}+...$的形式。因为K相当小,可以先搜出每个$K$下的拆分情况,问题就转化成了求$[l,r]$之间有多少数至少是其中一个的倍数——这是一个相当经典的问题。

    但是这题的数据范围要求进一步细节优化。

    注意到在极限数据$K=7,T=5*10^4$下,纯粹地$2^{因数}$枚举每一种情况lcm的做法相当低效。通过观察/经验会发现,这$2^{因数}$个lcm有大量是重复的。那么我们就转而保存每个lcm的系数而非把lcm全部存下来。

    这是一个计算倍数容斥问题时,显著而不甚易想起的优化。

    代码很丑。没心情重构。

      1 #include<bits/stdc++.h>
      2 const int ass5[7] = {0, 5, 6, 8, 9, 14, 21};
      3 const int ass6[7] = {0, 6, 8, 10, 14, 44, 52};
      4 const int ass7[16] = {0, 7, 8, 9, 10, 12, 15, 22, 33, 39, 52, 55, 68, 102, 114, 138};
      5 typedef long long ll;
      6 
      7 int T;
      8 ll l,r,k,gmpAss5[40035],gmpAss6[40035],gmpAss7[40035];
      9 
     10 ll read()
     11 {
     12     char ch = getchar();
     13     ll num = 0, fl = 1;
     14     for (; !isdigit(ch); ch = getchar())
     15         if (ch=='-') fl = -1;
     16     for (; isdigit(ch); ch = getchar())
     17         num = (num<<1)+(num<<3)+ch-48;
     18     return num*fl;
     19 }
     20 int gcd(int a, int b){return !b?a:gcd(b, a%b);}
     21 ll assp5(ll x)
     22 {
     23     ll ret = 0;
     24     for (int i=1; i<64; i++)
     25         ret += x/gmpAss5[i];
     26     return ret;
     27 }
     28 ll assp6(ll x)
     29 {
     30     ll ret = 0;
     31     for (int i=1; i<64; i++)
     32         ret += x/gmpAss6[i];
     33     return ret;
     34 }
     35 ll assp7(ll x)
     36 {
     37     ll ret = 0;
     38     for (int i=1; i<=gmpAss7[0]; i++)
     39         if (gmpAss7[i]) ret += x/gmpAss7[i];
     40     return ret;
     41 }
     42 void makeAss5()
     43 {
     44     for (int i=1, ass=6; i<(1<<(ass)); i++)
     45     {
     46         ll dt = 0, lst = 1, del;
     47         for (int j=1, t=i; j<=ass; j++, t>>=1)
     48             if (t&1){
     49                 ++dt, del = gcd(lst, ass5[j]);
     50                 lst *= ass5[j]/del;
     51             }
     52         gmpAss5[i] = (dt&1)?lst:-lst;
     53     }
     54 }
     55 void makeAss6()
     56 {
     57     for (int i=1, ass=6; i<(1<<(ass)); i++)
     58     {
     59         ll dt = 0, lst = 1, del;
     60         for (int j=1, t=i; j<=ass; j++, t>>=1)
     61             if (t&1){
     62                 ++dt, del = gcd(lst, ass6[j]);
     63                 lst *= ass6[j]/del;
     64             }
     65         gmpAss6[i] = (dt&1)?lst:-lst;
     66     }
     67 }
     68 void makeAss7()
     69 {
     70     ll &tot = gmpAss7[0];
     71     for (int i=1, ass=15; i<(1<<(ass)); i++)
     72     {
     73         ll dt = 0, lst = 1, del;
     74         for (int j=1, t=i; j<=ass; j++, t>>=1)
     75             if (t&1){
     76                 ++dt, del = gcd(lst, ass7[j]);
     77                 lst *= ass7[j]/del;
     78             }
     79         lst = (dt&1)?lst:-lst;
     80         bool chk = 1;
     81         for (int i=1; i<=tot&&chk; i++)
     82             if (gmpAss7[i]==-lst) gmpAss7[i] = 0, chk = 0;
     83         if (chk) gmpAss7[++tot] = lst;
     84     }
     85 }
     86 ll calc(ll x, ll k)
     87 {
     88     ll ret = 0;
     89     if (k==1) return x;
     90     if (k==2) return x>>1;
     91     if (k==3) return (x/3+x/4-x/12);
     92     if (k==4) return (x/4+x/6+x/10-x/12-x/30-x/20+x/60);
     93     if (k==5) return assp5(x);
     94     if (k==6) return assp6(x);
     95     if (k==7) return assp7(x);
     96     return ret;
     97 }
     98 void write(ll x){if (x/10) write(x/10);putchar(x%10+'0');}
     99 int main()
    100 {
    101     makeAss5(), makeAss6(), makeAss7();
    102     for (scanf("%d",&T); T; --T)
    103     {
    104         l = read(), r = read(), k = read();
    105         write(calc(r, k)-calc(l-1, k)), putchar('
    ');
    106     }
    107     return 0;
    108 }

    END

  • 相关阅读:
    ORA-01940: cannot drop a user that is currently connected解决方法
    Git基本用法简介
    C 入门 第十节 存储区
    C 入门 第九节 结构体指针
    C 入门 第八节 指针
    C 入门 第七节 结构体
    C 入门 第六节 自定义函数
    C 入门 第五节 多维数组 字符串数组
    C 入门 第四节
    C 入门 第三节
  • 原文地址:https://www.cnblogs.com/antiquality/p/10357448.html
Copyright © 2011-2022 走看看