Tag Archives: 素数

hihoCoder 1493-歌德巴赫猜想

hihoCoder 1493-歌德巴赫猜想

#1493 : 歌德巴赫猜想

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

哥德巴赫猜想认为“每一个大于2的偶数,都能表示成两个质数之和”。 给定一个大于2的偶数N,你能找到两个质数P和Q满足P<=Q并且P+Q=N吗?

输入

一个偶数N(4 <= N <= 1000000)

输出

输出P和Q。如果有多组解,输出P最小的一组。
样例输入
10
样例输出
3 7

给定一个大于2的偶数N,找出两个质数P和Q,满足P<=Q且P+Q=N。 我还以为这题有什么数论技巧,没想到直接从小到大暴力枚举P就行了。。。 代码如下: [cpp] #include<cstdio> #include<cmath> #include<iostream> using namespace std; bool isPrim(int x) { if (x < 2)return false; for (int i = 2; i <= sqrt(x); ++i) { if (x%i == 0)return false; } return true; } int main() { int N; scanf("%d", &N); for (int i = 2; i <= N / 2; ++i) { if (isPrim(i) && isPrim(N – i)) { printf("%d %d\n", i, N – i); return 0; } } return 0; } [/cpp] 本代码提交AC,用时0MS。]]>

LeetCode Count Primes

204. Count Primes

Count the number of prime numbers less than a non-negative number, n.

Example:

Input: 10
Output: 4
Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7.

本题要求从1~n共有多少个素数。Hint里一步步深入写得非常详细了,简要概括一下,有两种方法,一种是常规的从1~n一个个判断是否为非数,另一种是比较巧妙的Hash方法。 常规方法。首先看看判断一个数n是否为素数的方法,因为如果n为合数,则n可以分解为p×q,又n=p×q=(√n)×(√n),假设p是较小数的话,则p≤(√n)。所以我们只需要从2~(√n)判断能否被n整除,时间复杂度为O(n0.5)。从1~n都需要判断是否为素数,所以总的时间复杂度为O(n1.5)。 完整代码如下:

class Solution {
private:
    bool isPrime(int x)
    {
        if (x <= 1)
            return false;
        for (int i = 2; i * i <= x; ++i) {
            if (x % i == 0)
                return false;
        }
        return true;
    }
public:
    int countPrimes(int n)
    {
        int ans = 0;
        for (int i = 1; i < n; ++i) {
            if (isPrime(i))
                ++ans;
        }
        return ans;
    }
};

本代码提交TLE,在n很大的时候无法通过测试。

后来看了Hint,解法还是很巧妙的。如果一个数n是素数,则n的倍数肯定不是素数了,比如2是素数,则4=2*2、6=2*3、8=2*4…这些数肯定就不是素数了。所以我们可以建立一个1~n的Hash表,表示一个数是否为素数。初始的时候Hash[1~n]=true。然后从2开始,如果Hash[i]为true,说明i是素数,则2*i, 3*i,…都不是素数了,即Hash[2*i], Hash[3*i]..=false。如果Hash[i]为false,说明i不是素数,则i可以分解为i=p*q,使得p(或q)为素数,则之前测试p时,已经把p的所有倍数都置为false了,而i的倍数肯定也是p的倍数,所以不需要对i的倍数再置false了。

循环的终止条件是i>(√n),和第一种解法的分析一样,如果某个合数x大于(√n),则其肯定有一个素因子i是小于(√n)的,所以在测试i时,就已经把x置为false了。

另外对于素数i,我们之前分析的是要把所有2*i, 3*i…都置为false。其实这里也可以优化,我们可以从i*i开始置为false,而不需要每次都从2*i开始。比如i=5,常规是要把所有2*5, 3*5, 4*5, 5*5,…都置为false,但其实2*5, 3*5, 4*5都已经被之前的素数2或3置为false了。所以每次我们只需要从i*i开始,下标以i递增的置为false就好。(从i*i到i*i+(i-1)之间的合数被比i小的合数置为false了)总的来说,这一题加速的技巧很多,完整代码如下:

class Solution {
public:
    int countPrimes(int n)
    {
        vector<bool> mark(n, true);
        for (int i = 2; i * i < n; ++i) {
            if (!mark[i])
                continue;
            for (int j = i * i; j < n; j += i) {
                mark[j] = false;
            }
        }
        int ans = 0;
        for (int i = 2; i < n; ++i)
            ans += (mark[i] ? 1 : 0);
        return ans;
    }
};

本代码提交AC,用时29MS。

HDOJ 5392-Infoplane in Tina Town

HDOJ 5392-Infoplane in Tina Town Infoplane in Tina Town Time Limit: 14000/7000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Total Submission(s): 1636 Accepted Submission(s): 385 Problem Description There is a big stone with smooth surface in Tina Town. When people go towards it, the stone surface will be lighted and show its usage. This stone was a legacy and also the center of Tina Town’s calculation and control system. also, it can display events in Tina Town and contents that pedestrians are interested in, and it can be used as public computer. It makes people’s life more convenient (especially for who forget to take a device). Tina and Town were playing a game on this stone. First, a permutation of numbers from 1 to n were displayed on the stone. Town exchanged some numbers randomly and Town recorded this process by macros. Town asked Tine,”Do you know how many times it need to turn these numbers into the original permutation by executing this macro? Tina didn’t know the answer so she asked you to find out the answer for her. Since the answer may be very large, you only need to output the answer modulo 3∗230+1=3221225473 (a prime). Input The first line is an integer T representing the number of test cases. T≤5 For each test case, the first line is an integer n representing the length of permutation. n≤3∗106 The second line contains n integers representing a permutation A1…An. It is guaranteed that numbers are different each other and all Ai satisfies ( 1≤Ai≤n ). Output For each test case, print a number ans representing the answer. Sample Input 2 3 1 3 2 6 2 3 4 5 6 1 Sample Output 2 6 Source BestCoder Round #51 (div.2) Recommend hujie | We have carefully selected several similar problems for you: 5395 5394 5393 5390 5389


此题和POJ 2369-Permutations类似,只是测试样例更多,数据规模更大,最后还要对某个大数取模。所以在求所有循环节长度的最小公倍数的时候,不能使用gcd转换的方法,需要先后使用因式分解和快速幂算法。 参考下面的例子理解分解质因数法求最小公倍数的方法。 60=2×2×3×5 18=2×3×3 lcm(60,18)=180=2×2×3×3×5 通过观察可以看出规律,要求a,b的最小公倍数,先将a和b分解成质因数相乘的形式,对于每一个质因子x,取x在a和b中出现频率最高的数作为x在最小公倍数中的频率。比如2在60中出现2次,但在18中只出现1次,所以2在最小公倍数180中也出现2次,同理质因子3和5分别出现2次和1次。 假设某个质因子x出现y次,则最后要计算$$x^ymodp$$,可以使用快速幂方法提高速度,该方法很好理解,将y看成二进制形式,如果y为偶数,则$$x^y=(x*x)^{y/2}$$;如果y为奇数,则$$x^y=x*x^{y-1}$$,y-1就是偶数了。同时modp就是快速幂取模了。 完整代码如下: [cpp] #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef unsigned long long ULL; const int kMaxN = 3000005, kNumPrime = 269; const ULL kMod = 3221225473; bool visited[kMaxN]; int permutation[kMaxN]; int prime[kNumPrime] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723 }; int prime_times[kMaxN]; //求x的所有质因子及其频率 void GetPrimeFactor(int x) { for (int i = 0; i < kNumPrime; i++) { int tmp = 0; while (x%prime[i] == 0) { tmp++; x /= prime[i]; } if (tmp > prime_times[prime[i]]) prime_times[prime[i]] = tmp; if (x == 1) return; } prime_times[x]++; } //快速幂取模x^ymod(kMod) ULL QuickPow(ULL x, ULL y) { ULL ans = 1; while (y) { if (y & 1) ans = (ans*x)%kMod; x = (x*x) % kMod; y >>= 1; } return ans; } int main() { int t, n, len; ULL ans; scanf("%d", &t); while (t–) { scanf("%d", &n); memset(visited, false, kMaxN); memset(prime_times, 0, kMaxN); for (int i = 1; i <= n; i++) scanf("%d", &permutation[i]); for (int i = 1; i <= n; i++) { if (!visited[i]) { visited[i] = true; int j = permutation[i]; len = 1; while (j != i) { visited[j] = true; j = permutation[j]; len++; } GetPrimeFactor(len); } } ans = 1; for (int i = 2; i < n; i++) if (prime_times[i] != 0) ans = (ans*QuickPow(i, prime_times[i])) % kMod; printf("%I64un", ans); } return 0; } [/cpp] 本代码提交AC,用时5101MS,内存27984K。]]>