zoukankan      html  css  js  c++  java
  • 【BZOJ 1128】数列

    题目大意:

    对于一个长度为$n$的数列$p$,数列中任意两个数互质。

    现在有一个无限长的储存器,从$p_1$开始,把储存器中$p_1$倍数位置都赋值为$p_1$,把储存器中$p_2$倍数位置都赋值为$p_2$,把储存器中$p_3$倍数位置都赋值为$p_3$,以此类推。

    求每个$p_i$在储存器中出现的比例,用分数表示。

    $n le 1000$、$p le 10^9$,需要用到高精度。

    分析:

    初步推导公式:

    根据题意,前面赋值过的数会被后面的数覆盖,所以可以从后往前推,那些被覆盖过的就忽略掉。

    易知,这些数在存储器中是循环出现的,周期为所有$p$的乘积,那么只要考虑区间$[1,prod_{i=1}^{n}p_i]$内的数就好了。

    对于每个数$p$,在这个区间内是$p_i$倍数的数的个数为$frac{prod_{i=1}^{n}p_i}{p}$,占所有数的比例为$frac{1}{p}$,然而还要减去那些会被后面覆盖的。而在被覆盖的数中,被$p_i$整除的数也是平均分布出现的。

    设$p_i$在存储器中出现的比例为$A_i$,那么就得到:

    $$A_i=frac{1}{p} - frac{1}{p}cdot sum_{j=i+1}^{n}A_j = frac{1}{p}(1-sum_{j=i+1}^{n}A_j)$$

    这样,就可以用一个$Sum$记录下$A_i$的后缀和,就可以线性推导公式了。

    最简分数形式:

    但是,仍然存在一个问题,那就是题目中要求的最简分数形式。

    取最简分数形式有两种方法,第一是找两个高精度数的$GCD$,第二种是枚举每个$p$看看能不能除。

    然而在高精度的情况下这两种方法都不可取,将高精度数的长度看作$n$,则不论哪种方法每次对一个分数进行简化就需要$O(n^2)$的复杂度,接合线性的推导,就需要$O(n^3)$的复杂度,显然会T。

    进一步推导:

    因为要用到$A_i$的后缀和,那么不妨再设$S_i=sum_{j=i+1}^{n}A_j$。

    然后就有:

    $$egin{array}\A_i&=&frac{1-S_i}{p_i} \S_{i-1} &=& S_i + A_i \ A_{i-1}&=&frac{1-S_{i-1}}{p_{i-1}} \ &=&frac{1-S_i-A_i}{p_{i-1}} \ &=&frac{A_icdot p_i-A{i}}{p_{i-1}} \ &=&A_icdot frac{p_i-1}{p_{i-1}} end{array}$$

    即:

    $$left { egin{array} \A_n&=&frac{1}{p_n} \A_i&=&A_{i+1}cdotfrac{p_{i+1}-1}{p_i} (i lt n) end{array} ight .$$

    这样就得到了另一个等价的递推式,而这个递推式的优点可以每次乘的同时进行分数化简,只要对一个高精度数和一个单精度数取$GCD$,或对两个单精度数取$GCD$,这样$GCD$的复杂度就变成了$O(n)$,整体复杂度为$O(n^2)$。

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 
      4 #define BNmod 1000000000ll
      5 
      6 struct BigNumber
      7 {
      8     long long m[1010];
      9 
     10     inline long long operator %(long long x)
     11     {
     12         long long last = 0;
     13         for (int i = 1009; i >= 0; i--)
     14         {
     15             last = last + m[i];
     16             last = last % x * BNmod;
     17         }
     18         return last / BNmod;
     19     }
     20 
     21     inline BigNumber operator *(long long x)
     22     {
     23         BigNumber Tmp;
     24         long long last = 0;
     25         for (int i = 0; i <= 1009; i++)
     26         {
     27             Tmp.m[i] = last + m[i] * x;
     28             last = 0;
     29             if (Tmp.m[i] >= BNmod)
     30             {
     31                 last = Tmp.m[i] / BNmod;
     32                 Tmp.m[i] %= BNmod;
     33             }
     34         }
     35         return Tmp;
     36     }
     37 
     38     inline BigNumber operator /(long long x)
     39     {
     40         BigNumber Tmp;
     41         long long last = 0;
     42         for (int i = 1009; i >= 0; i--)
     43         {
     44             Tmp.m[i] = last + m[i];
     45             last = Tmp.m[i] % x * BNmod;
     46             Tmp.m[i] /= x;
     47         }
     48         return Tmp;
     49     }
     50 
     51     inline void Print()
     52     {
     53         int flag = 0;
     54         for (int i = 1009; i >= 0; i--)
     55         {
     56             if (flag == 0 && m[i] > 0)
     57             {
     58                 flag = 1;
     59                 printf("%lld", m[i]);
     60             }
     61             else
     62             {
     63                 if (flag == 1)
     64                 {
     65                     printf("%09lld", m[i]);
     66                 }
     67             }
     68         }
     69         if (flag == 0) putchar('0');
     70     }
     71 } FZ, FM, ans[1010][2];
     72 
     73 int n, p[1010];
     74 
     75 long long gcd(long long a, long long b)
     76 {
     77     return b ? gcd(b, a % b) : a;
     78 }
     79 
     80 long long gcd(BigNumber a, long long b)
     81 {
     82     return b ? gcd(b, a % b) : 1;
     83 }
     84 
     85 int main()
     86 {
     87     scanf("%d", &n);
     88     for (int i = 1; i <= n; i++)
     89     {
     90         scanf("%d", &p[i]);
     91     }
     92     memset(FZ.m, 0, sizeof(FZ.m));
     93     memset(FM.m, 0, sizeof(FM.m));
     94     FZ.m[0] = 1, FM.m[0] = p[n];
     95     ans[n][0] = FZ;
     96     ans[n][1] = FM;
     97     for (int i = n - 1; i > 0; i--)
     98     {
     99         int a = p[i + 1] - 1, b = p[i];
    100         int d = gcd(a, b); a /= d, b /= d;
    101         d = gcd(FZ, b); FZ = FZ / d; b /= d;
    102         d = gcd(FM, a); FM = FM / d; a /= d;
    103         FZ = FZ * a; FM = FM * b;
    104         int f = 0;
    105         for (int j = 0; j < 1010; j++)
    106             f += (FZ.m[j] > 0);
    107         if (f == 0)
    108         {
    109             memset(FM.m, 0, sizeof(FM.m));
    110             FM.m[0] = 1;
    111         }
    112         ans[i][0] = FZ; ans[i][1] = FM;
    113     }
    114     for (int i = 1; i <= n; i++)
    115     {
    116         ans[i][0].Print();
    117         printf("/");
    118         ans[i][1].Print();
    119         printf("
    ");
    120     }
    121 }
  • 相关阅读:
    bzoj1015星球大战(并查集+离线)
    bzoj1085骑士精神(搜索)
    bzoj1051受欢迎的牛(Tarjan)
    左偏树学习
    hdu1512 Monkey King(并查集,左偏堆)
    左偏树(模板)
    PAT (Basic Level) Practice (中文) 1079 延迟的回文数 (20分) (大数加法)
    PAT (Basic Level) Practice (中文) 1078 字符串压缩与解压 (20分) (字符转数字——栈存放)
    PAT (Basic Level) Practice (中文) 1077 互评成绩计算 (20分) (四舍五入保留整数)
    PAT (Basic Level) Practice (中文) 1076 Wifi密码 (15分)
  • 原文地址:https://www.cnblogs.com/lightning34/p/4603907.html
Copyright © 2011-2022 走看看