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 }
  • 相关阅读:
    《掌握需求过程》阅读笔记(二)
    《掌握需求过程》阅读笔记(一)
    《软件方法》阅读笔记(三)
    《软件方法》阅读笔记(二)
    《软件方法》阅读笔记(一)
    《大象Think in UML》阅读笔记(三)
    Java中toArray的用法探究(java数组与list转换)
    Eclipse调试常用技巧
    ListView 总结----持续中
    PowerDesigner提示This data item is already used in a primary identifier.的处理
  • 原文地址:https://www.cnblogs.com/lightning34/p/4603907.html
Copyright © 2011-2022 走看看