zoukankan      html  css  js  c++  java
  • 《挑战程序设计竞赛》2.6 数学问题-素数 AOJ0009 POJ3126 3421 3292 3641

    AOJ0009

    http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0009

    题意

    求不大于n的素数个数。

    思路

    素数筛法可解,筛法过程中可顺便统计不大于n的素数个数。
    另外这个题由于有多个测试数据,可预先求出题目所给数据范围的所有解。
    素数筛法中我的写法里要注意数的范围,这个题中的i*i是可能超过int表示范围的,因而我提交了好几次都是RE,需要提前判断。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int N = 1000000;
    
    bool prime[N];
    int num[N];
    
    int main(void)
    {
        fill(prime, prime+N, true);
        fill(num, num+N, 0);
        prime[1] = false;
        for (int i = 2; i < N; i ++) {
            num[i] = num[i-1];
            if (prime[i]) {
                num[i] ++;
                if (i > (int)sqrt((double)N)) continue;
                for (int j = i*i; j < N; j += i) {
                    prime[j] = false;
                }
            }
        }
    
        int n;
        while (scanf("%d", &n) != EOF)
            printf("%d
    ", num[n]);
    
        return 0;
    }

    POJ3126

    http://poj.org/problem?id=3126

    题意

    给定两个四位素数a b,要求把a变换到b。
    变换的过程要保证每次变换出来的数都是一个四位素数,而且当前这步的变换所得的素数与前一步得到的素数只能有一个位不同,而且每步得到的素数都不能重复。

    思路

    这个题其实主要考的是BFS,素数判定只是其中的条件判定依据。此处的素数构造用的是素数筛法。

    代码

    Source Code
    
    Problem: 3126       User: liangrx06
    Memory: 260K        Time: 16MS
    Language: C++       Result: Accepted
    Source Code
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    const int N = 10000;
    const int INF = 10000;
    
    bool isPrime[N];
    
    void initPrime()
    {
        for (int i = 0; i < N; i ++)
            isPrime[i] = true;
        for (int i = 2; i < N; i ++) {
            if (isPrime[i]) {
                for (int j = i*i; j < N; j += i)
                    isPrime[j] = false;
            }
        }
    }
    
    int d[N];
    
    int exp10(int x)
    {
        int res = 1;
        while (x--)
            res *= 10;
        return res;
    }
    
    int BFS(int begin, int end)
    {
        int i, j;
        queue <int> q;
        for (i = 1000; i < N; i++)
            d[i] = INF;
        q.push(begin);
        d[begin] = 0;
    
        while( q.size() ) {
            int p = q.front();
            q.pop();
            if (p == end) break;
    
            for (i = 1; i <= 1000; i *= 10) {
                int m = (p/i) % 10;
                for (j = 0; j <= 9; j ++) {
                    if (j == m) continue;
                    if (j == 0 && i == 1000) continue;
                    int n = p + (j-m) * i;
                    if (isPrime[n] && d[n] == INF) {
                        q.push(n);
                        d[n] = d[p] + 1;
                    }
                }
            }
        }
    
        return d[end];
    }
    
    int main(void)
    {
        int t, begin, end;
    
        initPrime();
        cin >> t;
        while (t--) {
            cin >> begin >> end;
            int res = BFS(begin, end);
            if (res == INF)
                printf("Imossible
    ");
            else
                printf("%d
    ", res);
        }
        return 0;
    }

    POJ3421

    http://poj.org/problem?id=3421

    题意

    给你一个数X,将X分解成1~X的因子数列,前一个数可以整数后一个数,求满足条件的最大链长以及有多少条这样长的链。

    思路

    容易想到因式分解,最大链长就是素数因子个数,链的个数即是全部素因子的排列数。
    若有m个素因子x1,x2,…,xm,每个素因子的个数为c1,c2,…,cm,素因子个数相加为C,则全部素因子排列数为:
    C!/(c1!c2!***cm!)

    代码

    Source Code
    
    Problem: 3421       User: liangrx06
    Memory: 208K        Time: 125MS
    Language: C++       Result: Accepted
    Source Code
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    const int N = 1024;
    
    bool isPrime[N+1];
    
    void initPrime()
    {
        int i, j;
        for (i = 0; i <= N; i ++)
            isPrime[i] = true;
        isPrime[0] = isPrime[1] = false;
        for (i = 2; i <= N; i ++) {
            if (isPrime[i]) {
                for (j = i*i; j <= N; j += i)
                    isPrime[j] = false;
            }
        }
    }
    
    typedef long long LL;
    typedef pair<LL, LL> P;
    
    LL fact(int n)
    {
        LL res = 1;
        while (n > 1) {
            res *= n;
            n --;
        }
        return res;
    }
    
    P solve(int n)
    {
        int i, j;
        queue<int> q;
        for (i = 2; i <= N; i ++) {
            if (!isPrime[i]) continue;
            if (n % i == 0) {
                j = 0;
                while (n % i == 0) {
                    n /= i;
                    j ++;
                }
                q.push(j);
                if (n == 1) break;
            }
        }
        if (n > 1)
            q.push(1);
    
        P res = P(0, 1);
        while (q.size()) {
            int m = q.front();
            q.pop();
            res.first += m;
            res.second *= fact(m);
        }
        res.second = fact(res.first) / res.second;
        return res;
    }
    
    int main(void)
    {
        int n;
        initPrime();
        while (cin >> n) {
            P res = solve(n);
            printf("%lld %lld
    ", res.first, res.second);
        }
        return 0;
    }

    POJ3292

    http://poj.org/problem?id=3292

    题意

    对于4*n+1(n为自然数)组成的集合,乘法在该集合中是封闭的。现规定h-prime是这个集合的数字中只有1和本身能整除的数(不含1)。其余为h合数。从h合数中划分出一部分数字,这些数是由两个h素数相乘得到的,称之为h-semi。现要求在指定1~n范围内有多少个h-semi。

    思路

    注意这里的素数区别于普通意义上的素数,要根据题目中给出的规则来判定。但求h-prime时仍可用素数筛法,求出h-prime后就可以以两两素数相乘的循环找出所有h-semi。

    代码

    Source Code
    
    Problem: 3292       User: liangrx06
    Memory: 3136K       Time: 16MS
    Language: C++       Result: Accepted
    Source Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    const int N = 1000001;
    
    bool isPrime[N+1];
    bool isSemi[N+1];
    int countSemi[N/4+1];
    
    void initPrime()
    {   
        int i;
        for (i = 0; i <= N; i ++)
            isPrime[i] = true;
        isPrime[0] = isPrime[1] = false;
        for (i = 5; i <= N; i += 4) {
            if (isPrime[i]) {
                if (i > (int)sqrt((double)N)) continue;
                for (int j = i*i; j <= N; j += 4*i)
                    isPrime[j] = false;
            }
        }
    }
    
    void initSemi()
    {
        int i, j;
        for (i = 1; i <= N; i += 4) {
            isSemi[i] = false;
            countSemi[i/4] = 0;
        }
        for (i = 5; i <= N; i += 4) {
            if (i > (int)sqrt((double)N)) break;
            for (j = i; j <= N; j += 4) {
                if (i * j > N) break;
                if (isPrime[i] && isPrime[j])
                    isSemi[i * j] = true;
            }
        }
        for (i = 5; i <= N; i += 4) {
            countSemi[i/4] = countSemi[i/4-1];
            if (isSemi[i])
                countSemi[i/4] ++;
        }
    }
    
    int main(void)
    {
        int n;
        initPrime();
        initSemi();
        while (cin >> n && n) {
            printf("%d %d
    ", n, countSemi[n/4]);
        }
        return 0;
    }

    POJ3641

    http://poj.org/problem?id=3641

    题意

    判断p是否是基于a的伪素数。输入p,a,两个数如果p是素数输出no,如果p不是素数,判断a^p%p==a是否成立,如果成立输出yes,否则输出no。

    思路

    这个题在书中分类到快速幂运算里面了,显然分类错误,应该分类到素数
    主要考察素数判定,这个题对时间复杂度要求不高,采用i从2到sqrt(n)能否整除n的方式就可以。

    代码

    Source Code
    
    Problem: 3641       User: liangrx06
    Memory: 212K        Time: 16MS
    Language: C++       Result: Accepted
    Source Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    typedef long long LL;
    
    bool isPrime(LL n)
    {
        int i;
        for (i = 2; i <= (LL)sqrt(double(n)); i ++) {
            if (n % i == 0)
                return false;
        }
        return true;
    }
    
    int main(void)
    {
        LL a, p;
    
        while (cin >> p >> a) {
            if (!p && !a) break;
    
            if (isPrime(p)) {
                printf("no
    ");
                continue;
            }
    
            LL p0 = p, a0 = a;
            LL res = 1;
            while (p0) {
                if (p0 % 2 == 1)
                    res = (res * a0) % p;
                a0 = (a0 * a0) % p;
                p0 /= 2;
            }
            if (res == a)
                printf("yes
    ");
            else
                printf("no
    ");
        }
    
        return 0;
    }
  • 相关阅读:
    网络世界中的图片以及相关的处理
    Ninject 2.x细说1.基本使用
    Orchard1.4新功能自动路由(AutoRouter)并附Orchard最新1.4版汉化包
    json的一点总结
    ASP.NET MVC路由扩展:路由映射
    厚积薄发,丰富的公用类库积累,助你高效进行系统开发(12) 网络相关操作辅助类
    IIS是如何处理ASP.NET请求的
    一周最新示例代码回顾 (3/19–3/25)
    .NET插件系统(三) 插件间通信问题——设计可自组织和注入的组装程序
    缓存总结
  • 原文地址:https://www.cnblogs.com/liangrx06/p/5083761.html
Copyright © 2011-2022 走看看