sicily_1009 Mersenne Composite N

題目

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB

Description

One of the world-wide cooperative computing tasks is the "Grand Internet Mersenne Prime Search" -- GIMPS -- striving to find ever-larger prime numbers by examining a particular category of such numbers.
A Mersenne number is defined as a number of the form (2p–1), where p is a prime number -- a number divisible only by one and itself. (A number that can be divided by numbers other than itself and one are called "composite" numbers, and each of these can be uniquely represented by the prime numbers that can be multiplied together to generate the composite number — referred to as its prime factors.)
Initially it looks as though the Mersenne numbers are all primes.

Prime Corresponding Mersenne Number

2 4–1 = 3 -- prime 
3 8–1 = 7 -- prime 
5 32–1 = 31 -- prime 
7 128–1 = 127 -- prime 

If, however, we are having a "Grand Internet" search, that must not be the case.
Where k is an input parameter, compute all the Mersenne composite numbers less than 2k -- where k <= 63 (that is, it will fit in a 64-bit signed integer on the computer). In Java, the "long" data type is a signed 64 bit integer. Under gcc and g++ (C and C++ in the programming contest environment), the "long long" data type is a signed 64 bit integer.

Input

Input is from file a. in. It contains a single number, without leading or trailing blanks, giving the value of k. As promised, k <= 63.

Output

One line per Mersenne composite number giving first the prime factors (in increasing order) separate by asterisks, an equal sign, the Mersenne number itself, an equal sign, and then the explicit statement of the Mersenne number, as shown in the sample output. Use exactly this format. Note that all separating white space fields consist of one blank.

Sample Input

31

Sample Output

23 * 89 = 2047 = ( 2 ^ 11 ) - 1
47 * 178481 = 8388607 = ( 2 ^ 23 ) - 1
233 * 1103 * 2089 = 536870911 = ( 2 ^ 29 ) - 1


題目大意

找出指數為63或以下的不是素數的梅森數。

思路

  1. 有限小個數答案的問題,效率最高的是枚舉所有可能的答案,也就是所謂的直接打表。(然而有作弊的嫌疑)
  2. 建立好素數表,然后從中篩選。(然而那么大量數據的表,還沒建好都TLE了)
  3. 簡單粗暴地對每個數進行質因數分解。(然而一定會TLE)
  4. 只針對符合答案的情況進行計算。(其實這樣子和打表沒有什么區別)

代碼

直接打表版

網上說算到59就夠了,是因為$2^{61}-1$是一個梅森素數,這里不用輸出。

// Copyright (c) 2015 HuangJunjie@SYSU(SNO:13331087). All Rights Reserved.
// sicily 1009: http://soj.sysu.edu.cn/1009
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

int main() {
  int max;
  int answer[9] = { 11, 23, 29, 37, 41, 43, 47, 53, 59 };
  long long int factor[10];
  scanf("%d", &max);

  for (int i = 0; i < 9 && answer[i] <= max; i++) {
    switch (answer[i]) {
      case 11:
        printf("23 * 89 = 2047 = ( 2 ^ 11 ) - 1\n");
        break;
      case 23:
        printf("47 * 178481 = 8388607 = ( 2 ^ 23 ) - 1\n");
        break;
      case 29:
        printf("233 * 1103 * 2089 = 536870911 = ( 2 ^ 29 ) - 1\n");
        break;
      case 37:
        printf("223 * 616318177 = 137438953471 = ( 2 ^ 37 ) - 1\n");
        break;
      case 41:
        printf("13367 * 164511353 = 2199023255551 = ( 2 ^ 41 ) - 1\n");
        break;
      case 43:
        printf("431 * 9719 * 2099863 = 8796093022207 = ( 2 ^ 43 ) - 1\n");
        break;
      case 47:
        printf("2351 * 4513 * 13264529 = 140737488355327 = ( 2 ^ 47 ) - 1\n");
        break;
      case 53:
        printf("6361 * 69431 * 20394401 = 9007199254740991 = ( 2 ^ 53 ) - 1\n");
        break;
      case 59:
        printf("179951 * 3203431780337 = 576460752303423487 = ( 2 ^ 59 ) - 1\n");
        break;
    }
  }

  return 0;
}

簡單粗暴版

大概10s以內的代碼, 里面的注釋能夠幫助理清思路。

// Copyright (c) 2015 HuangJunjie@SYSU(SNO:13331087). All Rights Reserved.
// sicily 1009: http://soj.sysu.edu.cn/1009
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

// get all prime numbers that is no more than num.
// @Param num: the max number that we want the primes less than.
// @return: a prime list.
vector<int> getPrime(int num) {
  vector<int> prime;
  prime.push_back(2);
  for (int i = 3; i <= num; i+=2) {
    bool isPrime = true;
    for (int j = 0; j < prime.size(); j++) {
      if (prime[j] * prime[j] > i) break;
      if (i % prime[j] == 0) {
        isPrime = false;
        break;
      }
    }
    if (isPrime) prime.push_back(i);
  }

  return prime;
}

int main() {
  // gets all posible exponents.
  vector<int> exponent = getPrime(63);

  int max;
  vector<long long int> factor;
  scanf("%d", &max);

  // exams the corresponding mersenne number for a exponent.
  // if the mersenne is a composite number, outputs it.
  for (int i = 0; i < exponent.size() && exponent[i] <= max; i++) {
    long long int mersenne = (1LL << exponent[i]) - 1;
    long long int temp = mersenne;

    // counts the factors.
    factor.clear();
    for (long long int j = 3; j*j < temp; j += 2) {
      if (temp%j == 0) {
        factor.push_back(j);
        temp /= j;
      }
    }
    // if @temp is less than @mersenne, which means that mersenne has some
    // factors, and temp is also a prime factor for it doesn't divide any
    // numbers less than its square root.
    if (temp < mersenne) factor.push_back(temp);

    // factors exists means mersenne is composite. outputs it.
    if (!factor.empty()) {
      for (int j = 0; j < factor.size(); j++) {
        if (j) printf(" * ");
        printf("%lld", factor[j]);
      }
      printf(" = %lld = ( 2 ^ %d ) - 1\n", mersenne, exponent[i]);
    }
  }

  return 0;
}

優化版

此版本是參考http://www.cnblogs.com/mjc467621163/archive/2011/07/04/2097278.html

只針對符合的結果運算,可能剩下超級多的時間。

// Copyright (c) 2015 HuangJunjie@SYSU(SNO:13331087). All Rights Reserved.
// sicily 1009: http://soj.sysu.edu.cn/1009
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

int main() {
  int max;
  int answer[9] = { 11, 23, 29, 37, 41, 43, 47, 53, 59 };
  long long int factor[10];
  scanf("%d", &max);

  for (int i = 0; i < 9 && answer[i] <= max; i++) {
    long long int mersenne = (1LL << answer[i]) - 1;
    long long int temp = mersenne;

    memset(factor, 0, sizeof(factor));
    
    int count = 0;
    for (long long int j = 3; j*j < temp; j+=2) {
      if (temp%j ==0) {
        factor[count++] = j;
        temp /= j;
      }
    }
    if (temp < mersenne) factor[count++] = temp;

    for (int j = 0; j < count; j++) {
      if (j) printf(" * ");
      printf("%lld", factor[j]);
    }
    printf(" = %lld = ( 2 ^ %d ) - 1\n", mersenne, answer[i]);
  }

  return 0;
}

以上兩個版本都存在不能檢驗重復因式的問題,所以對優化版的因子判斷(21-28行)進行小改良

    int count = 0;
    for (long long int j = 3; j*j < temp; j += 2) {
      if (temp%j == 0) {
        while (temp%j == 0) {
          factor[count++] = j;
          temp /= j;
        }
      }
    }
    if (temp < mersenne) factor[count++] = temp;

參考

http://m.blog.csdn.net/blog/zhanweeleee/40949933
http://www.cnblogs.com/mjc467621163/archive/2011/07/04/2097278.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 9,828評論 0 23
  • 昨夜睡夢中又有些抽筋,只是肌肉作痛,本不想再跑,偷懶一天,不過還是堅持去跑了。去的路上見一貓自在的臥于路邊車的車頂...
    goldfish2017閱讀 277評論 0 0
  • 現在的我們都是處于亞健康狀態,沒有一個人敢肯定的說“我沒病”這三個字。外表的健康不代表內在的零件已經脫落或衰竭。 ...
    PXX秘密之地閱讀 288評論 0 0
  • 她總對人說自己最喜歡的點心是湯圓。 在北方他們都管它叫元宵,她還是喜歡從小習慣了的名字。 湯圓和元宵有什么樣的區別...
    Lain_M閱讀 967評論 7 5
  • 158家已開始2016校招名企列表 互聯網(35家) 攜程:http://pages.ctrip.com/xyzp...
    丁叮當ss閱讀 872評論 0 2