相乘和比较大数字

Multiplying and comparing big numbers

本文关键字:数字 比较      更新时间:2023-10-16

我有这个问题:有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%的测试用例。有没有一种方法可以优化我的代码?

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

如果您想避免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的素数
  • 所以你可以制作一个素数的静态表来检查,以加快速度
  • 检查素数大于实际子结果也是没有意义的
  • 如果你知道怎么做,那么埃拉托斯特尼的Sieves可以极大地加快速度
  • 但您需要跟踪每次除法后的索引偏移量,并使用周期性筛选表,这有点复杂,但可行
  • 如果你不检查所有素数,只检查几个选定的素数
  • 那么结果仍然可能溢出
  • 所以你也应该处理它(抛出一些错误或其他什么)
  • 或者将所有子结果除以某个值,但这可能会使结果无效

另一种乘法方法

  • 也可以按值对被乘数进行排序
  • 并检查是否在所有最大行中都存在一些
  • 如果是,则将其更改为一个(或从列表中删除)
  • 这可以与前面的方法相结合

二进制乘法

  • 你可以自己做bignum乘法
  • 结果是最大20*32=640位
  • 所以结果将是无符号整数的数组(位宽8,16,32…随便你喜欢)
  • 您也可以将数字作为字符串处理
  • 关于如何在C中快速精确地计算bignum平方,请看这里++
  • 它还包含乘法方法
  • 这里是基于NTT的C中的Schönhage-Strassen乘法++
  • 但对于像你这样的小数字来说,速度会慢一些
  • 最后你需要比较结果
  • 因此,与MSW和LSW相比,哪一条线中的数字更大是最大线
  • (MSW是最高有效词,LSW是最低有效词)

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

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

如果你的乘积在[0,1]的范围内,那么它的对数将为负,这将使它为正。我认为你应该把它分开。