【问题标题】:Multiplying and comparing big numbers乘法和比较大数字
【发布时间】:2015-06-22 19:38:02
【问题描述】:

我有这个问题: 有 K 行 N 个数字(32 位)。我必须选择具有最大数字乘积的行。

主要问题是 N 可以达到 20。 我正在尝试用对数来做到这一点:

ld sum = 0, max = 0;
int index = 0;

for(int i = 0; i < k; i ++) { // K lines
    sum = 0, c = 0;
    for(int j = 0; j < n; j ++) { // N numbers
        cin >> t;
        if(t < 0)
            c++; // If the number is less than 0 i memorize it

        if(t == 1 || t == -1) { // if numbers = 1 OR -1
            sum += 0.00000001; // Because log(1) = 0
            if(t == -1)
                c ++;
        }
        else if(t == 0) { // if some number is equal to zero then the sum is = 0
            sum = 0;
            break;
        }
        else {
            sum += log10(fabs(t));
        }
    }

    if(c % 2 == 1) // if c is odd than multiply by -1
        sum *= -1;

    if(sum >= max) { 
        max = sum;
        index = i;
    }
    if((sum - max) < eps) { // if sum is equal to max i'm also have to choose it
        max = sum;
        index = i;
    }
}
cout << index + 1 << endl;

该程序适用于 50% 的测试用例。有没有办法优化我的代码?

【问题讨论】:

  • 您的程序只运行了一半,您想优化它吗?先让它工作......
  • @Borgleader 对不起我的英语,我只是找不到合适的词。我只想说也许计算有任何错误,或者你可以分享我可以找到信息的链接,谢谢!
  • 那么 long double 的精度(我认为这是 ld 的 typedef'd 吗?)不足以代表您的产品。您应该使用任意精度的算术,例如 GMP 库或 Java 的 BigInteger 类提供的。
  • 您是否尝试过将浮点值相乘?您将在现代台式 PC 上遇到的那种环境提供了范围远远超过 2^620 的双精度算术。当然,要获得精确的答案,您仍然需要多精度整数运算。
  • (如果这是一场比赛,请说明并提供链接。)(请说明numbers (32-bit) 是什么 - 假设自然,如果允许负整数,请说明什么是抢手的:最高有符号绝对乘积。)尝试除草 - 剔除因子1,产品至少包含一个因子0。考虑素数分解:计算每个素数和乘积。如果产品 a 的计数没有大于 b 并且至少小于一个,则丢弃产品 b。减去每个素数的最小计数。相乘和比较。

标签: c++ algorithm optimization biginteger


【解决方案1】:

在 t == -1 的情况下,您将 c 递增两次。

【讨论】:

    【解决方案2】:

    如果你想避免使用 bignum 库,你可以利用它,如果你将 b1b2 位数字相乘,那么结果就是 b1+b2 位长

    1. 所以只需将一行中所有乘数的位数相加

      • 并进行比较
      • 记住某个数组中的结果

        int bits(DWORD p) // count how many bits is p DWORD is 32bit unsigned int
            {
            DWORD m=0x80000000; int b=32;
            for (;m;m>>=1,b--)
             if (p>=m) break;
            return b;
            } 
        
    2. index 按结果位计数降序对行进行排序

    3. 如果排序后的第一位也是最大值,那么它的行就是答案
    4. 如果您有不止一个最大值(更多行具有相同的位数并且也是最大值)
      • 只有这样你才需要将它们相乘

    现在是乘法

    • 您知道应该一次将所有最大行数相乘
    • 每次所有子结果都可以被同一个素数整除
    • 除以它
    • 这样,结果将被截断为更少的位数
    • 所以它应该适合 64 位值
    • 你应该检查素数直到 sqrt(最大值)
    • 当您的最大值为 32 位时,请检查最高 65536 的素数
    • 因此您可以制作一个静态素数表来检查以加快速度
    • 也没有必要检查大于实际子结果的素数
    • 如果您知道如何使用 Eratosthenes 的筛子极大地加速这一过程
    • 但您需要在每次划分后跟踪索引偏移量并使用周期筛表,这有点复杂但可行
    • 如果您不检查所有素数,而只检查少数选定的素数
    • 那么结果还是会溢出
    • 所以你也应该处理它(抛出一些错误或其他东西)
    • 或将所有子结果除以某个值,但这会使结果无效

    另一种乘法方法

    • 您还可以按值对乘数进行排序
    • 并检查是否有一些存在于所有最大行中
    • 如果是,则将它们更改为一个(或从列表中删除)
    • 这可以与之前的方法结合使用

    大数乘法

    • 您可以进行自己的 bignum 乘法
    • 结果最大为 20*32=640 位
    • 所以结果将是无符号整数数组(位宽 8,16,32 ...随你喜欢)
    • 您也可以将数字作为字符串处理
    • 在这里查看如何计算fast exact bignum square in C++
    • 它还包含乘法方法
    • 这里是NTT based Schönhage-Strassen multiplication in C++
    • 但是对于像你这样的小数字来说,这会比较慢
    • 最后你需要比较结果
    • 因此,从 MSW 与 LSW 进行比较,哪条线中的数字更大就是最大线
    • (MSW 是最高有效字,LSW 是最低有效字)

    【讨论】:

    • @Rasul btw bits(x)=ceil(log2(x))=ceil(log10(x)/log10(2))=ceil(ln(x)/ln(2)) 所以它类似于您的方法,但仅适用于整数算术
    【解决方案3】:

    我认为这行肯定是错误的:

    if(c % 2 == 1) // if c is odd than multiply by -1
        sum *= -1;
    

    如果您的产品在 [0,1] 范围内,则其对数将为负数,这将使其为正数。我认为你应该把它分开。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-14
      • 2016-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-26
      相关资源
      最近更新 更多