zoukankan      html  css  js  c++  java
  • The 19th Zhejiang University Programming Contest Sponsored by TuSimple (Mirror) B"Even Number Theory"(找规律???)

    传送门

    题意:

      给出了三个新定义:

    1. E-prime : ∀ num ∈ E,不存在两个偶数a,b,使得 num=a*b;(简言之,num的一对因子不能全为偶数)
    2. E-prime factorization : 定义集合P由 E-prime 元素组成,定义 e = p1*p2*.....*pn;(p1,p2,....,pn ∈ P , |P| = n)
    3. E-factorial : 定义 e!! = 2*4*6*8*.........*e;(简言之,偶数e及其之前的偶数连乘积)

      输出一个数 e ,求满足条件2的集合P,并且集合P需满足:p1*p2*.....*p= e!! , |P| = n;

      求 n 的最大值;

     题解:

      定义集合 Pi 为偶数 i 的满足条件(2)的最大的集合

      例如P8 = {2,2,2},| P8 | = 3;

      根据贪心的思想,要想使集合 Pe!! 中的元素个数最多,那么,e!! 一定要优先分解出最多的2(最小的e-prime);

      定义 odd 表示奇数,那么 odd*2 为 e-prime,因为 odd 因式分解肯定没有偶数因子,odd*2 只能分解出一个偶数因子2,符合条件(1);

      因此,对于所有的奇数 odd,可以通过让 odd*2 将 odd 转化为 e-prime,那么,我们的关注点就变成了 e!! 最多能分解出多少个2

      对于 e 之前的所有偶数,假设 ≤ e 的最大的2的幂为 2x+1,那么对于 e 之前的所有2的幂 21,22,23,....,2x+1 其可分解出 1+2+3+......+x+1 个2;

      那 e 之前的所有非2的幂的偶数 even ,该如何快速求出他们的乘积最多能分解出多少个2呢?

      首先,求解一下 2x+1 及其之前的偶数乘积最多可以分解出多少个2;

      首先考虑这一点,任何一个偶数 even 都可分解成 odd*2i 模式, 那么 |Peven | = i;

      那么,我们反过来考虑,对于任意奇数 odd 都可通过 odd*2i 求出 | Podd*2i | = i;

      

          (每两个相邻的2的幂间的偶数块用红色编号① ② ③ ④ ...........表示)

          (紫色数字代表相邻的2的幂间的奇数的个数)

      对于偶数块①:只有一个奇数 3;

      3*21 来到偶数块②;

      3*22 来到偶数块③;

      3*23 来到偶数块④;

      ........

      3*2x-1来到偶数块(x);

      (注意偶数块的编号和2的幂的关系)

      可知,通过3*2可求出P3*21 , P3*22 , .........., P3*2x-1,其集合元素个数总和为 1+2+3+..........+(x-1);

      那么,对于偶数块 2 中的某一奇数 odd 呢?

      根据对3的分析,可知,偶数块②可以构成的 ≤ 2x+1 的最大的偶数为 odd*2x-2 ,那么,通过 odd 求出的集合Podd*2i 的元素个数总和为 1+2+3+.......+(x-2)

      因为偶数块②有21个奇数,所以这些奇数可以求出的集合P的元素个数总和为 2*(1+2+3+........+(x-2) );

      偶数块③有22个奇数,其中任意一个 odd 可构成的 ≤ 2x+1 的最大的偶数为 odd*2x-3 ,这些奇数可以求出的集合P的元素个数总和为 22*(1+2+......+(x-3) );

      ..............

      偶数块(x-1)有2x-2个奇数,其可求出的集合P的元素个数总和为2x-2;

      综上,2x+1 及其之前的偶数乘积最多可以分解出的2的个数为:

      

      这几项加和的值等于 2x+1-1;

      (并不是通过公式化简成这个最简式,而是通过打表找到的,公式化简的话,只能依靠那些大佬了QWQ)

      打表推公式代码:(明天张贴)

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 int Sum(int pow,int up)
     6 {
     7     int sum=0;
     8     for(int i=1;i <= up;++i)
     9         sum += i;
    10     return sum*pow;
    11 }
    12 int main()
    13 {
    14     int x;
    15     while(~scanf("%d",&x))
    16     {
    17         int sum=Sum(1,x);
    18         int base=1;
    19         for(int i=1;i <= x-2;++i)
    20         {
    21             sum += Sum(base,x-1-i);
    22             base *= 2;
    23         }
    24         printf("sum=%d,%d
    ",sum,1<<x);
    25     }
    26 }
    View Code

      那么,如果 e 为2的幂,直接输出 e-1;

      如果不是,先求出 ≤ e 的最大的2的幂 2x+1 ,记录当前答案 ans = 2x+1-1;

      那[2x+1 , e]之间的解该如何求出呢?

      还是考虑 odd*2i 的模式;

      令 odd1 ∈ [ 2x+1 / 2 , e / 2],∀odd1 * 2 ∈ [ 2x+1 , e ],且为 e-prime,ans += tot1*1;(tot为奇数个数)

      令 odd2 ∈ [ 2x+1 / 4 , e / 4],∀odd2 * 4 ∈ [ 2x+1 , e ],且为 e-prime,ans += tot2*2;

      .............

      令 oddk ∈ [ 2x+1 / 2k , e / 2k],∀oddk * 2x ∈ [ 2x+1 , e ],且为 e-prime,ans += totk*k;

      结束的条件是  2x+1 / 2k = e / 2k

    AC代码:(C++版大数伪码)(明天张贴)

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define BigInteger long long
     5 
     6 BigInteger e;
     7 BigInteger base;
     8 
     9 BigInteger F()
    10 {
    11     BigInteger curBase=2;
    12     BigInteger ans=0;
    13     BigInteger l=base/curBase;
    14     BigInteger r=e/curBase;
    15     for(int i=1;i < 4000;++i)
    16     {
    17 //        cout<<l<<' '<<r<<endl;
    18         if(l >= r)
    19             break;
    20         BigInteger tmp=(r-l)/2;
    21         if(r&1)
    22             tmp++;
    23         ans=ans+tmp*i;
    24         l=l/2;
    25         r=r/2;
    26     }
    27     return ans;
    28 }
    29 void Solve()
    30 {
    31     base=1;
    32     while(base*2 <= e)
    33         base *= 2;
    34     BigInteger ans=base-1;
    35 
    36     if(base != e)
    37         ans=ans+F();
    38 
    39     cout<<ans<<endl;
    40 }
    41 int main()
    42 {
    43     int test;
    44     while(cin>>test)
    45     {
    46         while(test--)
    47         {
    48             cin>>e;
    49             Solve();
    50         }
    51     }
    52     return 0;
    53 }
    C++版 BigInteger(逃)

    AC代码:(Java BigInteger类)(明天张贴)

     1 import java.math.BigInteger;
     2 import java.util.Scanner;
     3 
     4 public class Main {
     5 
     6     static Scanner cin = new Scanner(System.in);
     7     static BigInteger e,base;
     8     static BigInteger zero=BigInteger.valueOf(0);
     9     static BigInteger one=BigInteger.valueOf(1);
    10     static BigInteger two=BigInteger.valueOf(2);
    11     public static void main(String[] args) {
    12         
    13         int test;
    14         while(cin.hasNext()) {
    15             test=cin.nextInt();
    16             for(int i=1;i <= test;++i) {
    17                 
    18                 e=cin.nextBigInteger();
    19                 Solve();
    20             }
    21         }
    22     }
    23     private static void Solve() {
    24         
    25         base=one;
    26         while(base.multiply(two).compareTo(e) <= 0)
    27             base=base.multiply(two);
    28 //        System.out.println(base);
    29         BigInteger ans=base.subtract(one);
    30         
    31         if(!base.equals(e))
    32             ans=ans.add(F());
    33         System.out.println(ans);
    34     }
    35     private static BigInteger F() {
    36 
    37         BigInteger curBase=two;
    38         BigInteger ans=zero;
    39         BigInteger l=base.divide(curBase);
    40         BigInteger r=e.divide(curBase);
    41         for(int i=1;i < 4000;++i) {
    42             
    43             if(l.compareTo(r) >= 0)
    44                 break;
    45             BigInteger tmp=(r.subtract(l)).divide(two);
    46             if(r.mod(two).intValue() != 0)
    47                 tmp=tmp.add(one);
    48             ans=ans.add(tmp.multiply(BigInteger.valueOf(i)));
    49             
    50             l=l.divide(two);
    51             r=r.divide(two);
    52         }
    53         return ans;
    54     }
    55 }
    View Code

    今晚比较嗨,比较尽兴;

    陪俺家宝宝乘轻轨去市里疯了一圈,返程的路上还做过了一站;

    哈哈哈,要一直陪着宝宝啊*_*

  • 相关阅读:
    【转】Linux世界驰骋——文件系统和设备管理
    【转】Linux的inode的理解
    【转】名企HR教你如何过网申
    【转】Unix的文件系统的内部结构,主要是超级块、inode相关知识
    【转】Unix系统的心脏Unix文件系统
    【转】Unix环境高级程序设计入门文件系统的相关编程(上)
    【转】电驴提示“该内容尚未提供权利证明,无法提供下载”之解决办法详解
    【转】第三节 UNIX文件系统结构
    测试网站各项性能的31 个免费在线工具 (转)
    恋爱
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10709026.html
Copyright © 2011-2022 走看看