Prime triplets (Project Euler 196)
hackerrank programming version
题目大意是定义了一个正整数的表,第一行是1,第二行是1,2,第三行1,2,3...定义prime triple是在表上八连通的三个质数。然后问某行有多少个质数至少在一个prime triple中。 行数 <= 1e7.
题解:
假设要求第n行的答案,只要把上2行和下2行的数都抠出来,然后判断一下就好了。问题转化为求[L,R]之间的质数,这里5行数,区间长度大概有5e7,所以要用modified 区间筛法。 参考 http://euler.stephan-brumme.com/196/ 。 没什么思维量,积累一个区间筛法模板。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int mod = 1e9 + 7; 6 7 char* isPrime; 8 LL bias; 9 10 vector<LL> eratosthenesOddSingleBlock(LL from, LL to) 11 { 12 vector<LL> primes; 13 if (from > to || to <= 1) return primes; 14 if (to == 2) 15 { 16 primes.push_back(2); 17 return primes; 18 } 19 if (!(from & 1)) ++from; 20 if (from > to) return primes; 21 22 if (from <= 2) primes.push_back(2), from = 3; 23 const int memorySize = (to - from) / 2 + 1; 24 char* isPrime = new char[memorySize]; 25 26 27 for (int i = 0; i < memorySize; i++) 28 isPrime[i] = 1; 29 for (LL i = 3; i*i <= to; i+=2) 30 { 31 if (i >= 3*3 && i % 3 == 0) 32 continue; 33 if (i >= 5*5 && i % 5 == 0) 34 continue; 35 if (i >= 7*7 && i % 7 == 0) 36 continue; 37 if (i >= 11*11 && i % 11 == 0) 38 continue; 39 if (i >= 13*13 && i % 13 == 0) 40 continue; 41 LL minJ = ((from+i-1)/i)*i; 42 if (minJ < i*i) 43 minJ = i*i; 44 if ((minJ & 1) == 0) 45 minJ += i; 46 for (LL j = minJ; j <= to; j += 2*i) 47 { 48 int index = j - from; 49 isPrime[index/2] = 0; 50 } 51 } 52 53 for (int i = 0; i < memorySize; i++) 54 if (isPrime[i]) primes.push_back(from + 2*i); 55 56 delete[] isPrime; 57 return primes; 58 } 59 60 61 bool checkPrime(LL val) 62 { 63 return isPrime[val - bias]; 64 } 65 66 inline LL getNumber(int r, int c) 67 { 68 return 1LL * (r - 1) * r / 2 + c; 69 } 70 71 bool checkCentre(int r, int c) 72 { 73 if (c < 0 || c > getNumber(r, c) || !checkPrime(getNumber(r, c))) return false; 74 int cnt = 0, x, y; 75 for (int dx = -1; dx <= 1; ++dx) 76 { 77 for (int dy = -1; dy <= 1; ++dy) 78 { 79 x = r + dx; 80 y = c + dy; 81 if (y < 0 || y > x) continue; 82 cnt += checkPrime(getNumber(x, y)); 83 if (cnt >= 3) return true; 84 } 85 } 86 return false; 87 } 88 bool check(int r, int c) 89 { 90 for (int dx = -1; dx <= 1; ++dx) 91 for (int dy = -1; dy <= 1; ++dy) 92 if (checkCentre(r + dx, c + dy)) 93 return true; 94 return false; 95 } 96 97 LL solve(int row) 98 { 99 if (row == 1) return 0; 100 if (row <= 3) return 5; 101 102 LL l = getNumber(row - 2, 1), r = getNumber(row + 2, row + 2); 103 vector<LL> primes = eratosthenesOddSingleBlock(l, r); 104 isPrime = new char[r - l + 1]; 105 memset(isPrime, 0, r - l + 1); 106 bias = l; 107 for (auto p: primes) isPrime[p - bias] = 1; 108 109 pair<int, int> pos; 110 LL res = 0, val = getNumber(row, 1); 111 for (int col = 1; col <= row; ++col) 112 { 113 if (checkPrime(val) && check(row, col)) 114 res += val; 115 ++val; 116 } 117 return res; 118 } 119 120 int main() 121 { 122 //freopen("out.txt", "w" , stdout); 123 124 int a, b; 125 cin >> a >> b; 126 cout << solve(a) + solve(b) << endl; 127 128 return 0; 129 }
Every day is meaningful, keeping learning!