zoukankan      html  css  js  c++  java
  • csu 1552: Friends 二分图 + Miller_Rabin

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1552

    把那n个数写两次,分成相同的两堆,判断相加是质数的,连一条边,然后找最大匹配,ans = 最大匹配 / 2

    做的时候一直超时,原来是Miller_Rabin的quick_pow那里需要quick_mul配合,不然溢出。

    #include <stdio.h>
    #include <stdlib.h>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <map>
    #include <time.h>
    #define clr(u,v); memset(u,v,sizeof(u));
    using namespace std;
    typedef long long LL;
    const int maxn = 100 + 20;
    const int check_time = 20;
    bool e[maxn][maxn];
    
    
    LL quick_mul(LL a, LL b, LL MOD) {
        //求解 a*b%MOD的算法        // 原理:2*19 = 2*(1+2+16)
        LL base = a % MOD;
        b %= MOD;  //  a*b%MOD 等价于 (a%MOD * b%MOD) % MOD;
        LL ans = 0; //记住是0 因为中间过程是加
        while (b) {
            if (b & 1) {
                ans = (ans + base); //直接取模慢很多
                if (ans >= MOD) ans -= MOD;
            }
            base = (base << 1); //notice
            if (base >= MOD) base -= MOD;
            b >>= 1;
        }
        return ans;
    }
    LL quick_pow(LL a, LL b, LL MOD) {  //求解 a^b%MOD的值
        LL base = a % MOD;
        LL ans = 1; //相乘,所以这里是1
        while (b) {
            if (b & 1) {
                ans = quick_mul(ans, base, MOD); //如果这里是很大的数据,就要用quick_mul
            }
            base = quick_mul(base, base, MOD);    //notice。注意这里,每次的base是自己base倍
            b >>= 1;
        }
        return ans;
    }
    bool check(LL a, LL n, LL x, LL t) { //以a为基。n-1写成了 2^t * k,判断n是否为合数
        LL ret = quick_pow (a, x, n); //先算 a^k%n 后来一直平方.平方t次
        LL last = ret; //last就是a^k次方这个值,看成整体。符合X^2这个公式
        for (int i = 1; i <= t; ++i) {
            ret = quick_mul(ret, ret, n); //平方他,last就是一个大X,ret是X^2
            if (ret == 1 && last != 1 && last != n - 1) return true; //合数
            last = ret;
        }
        if (ret != 1) return true; //费马小定理,如果a^(n-1)%n != 1就绝逼不是素数
        return false;
    }
    bool Miller_Rabin(LL n) { //判断n是否质数
        if (n < 2) return false;
        if (n == 2) return true;
        if (n % 2 == 0) return false; //偶数不是质数
        LL k = n - 1;
        LL t = 0; //把n-1拆成 2^t * k 这种形式,那么从k开始验证,a^k,不断平方即可
        while ( (k & 1) == 0 ) { //如果x还是偶数的话,就是还有2的因子
            k >>= 1;
            t++;
        }
        for (int i = 1; i <= check_time; i++) {
            LL a = rand() % (n - 1) + 1; //最大去到n-1,[1,n-1]
            if (check (a, n, k, t)) //n-1写成了 2^t * k.米勒测试
                return false; //合数
        }
        return true; //质数
    }
    
    LL arr[maxn];
    int n;
    int match[maxn];
    bool vis[maxn];
    int dfs(int u) {
        for (int i = 1; i <= n; ++i) {
            if (!vis[i] && e[u][i]) {
                vis[i] = true;
                if (match[i] == 0 || dfs(match[i])) {
                    match[i] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int hungary() {
        memset(match, 0, sizeof match);
        int ans = 0;
        for (int i = 1; i <= n; ++i) {
            memset(vis, false, sizeof vis);
            if (dfs(i)) ans++;
        }
        return ans / 2;
    }
    void work() {
        memset(e, false, sizeof e);
    //    memset(match, 0, sizeof match);
        for (int i = 1; i <= n; ++i) {
            scanf("%lld", &arr[i]);
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = i + 1; j <= n; ++j) {
                if (Miller_Rabin(arr[i] + arr[j])) {
                    e[i][j] = true;
                    e[j][i] = true;
                }
            }
        }
    //    for (int i = 1; i <= n; ++i) {
    //        for (int j = 1; j <= n; ++j) {
    //            cout << e[i][j] << " ";
    //        }
    //        cout << endl;
    //    }
        printf("%d
    ", hungary());
    }
    
    int main() {
    #ifdef local
        freopen("case.in", "r", stdin);
    //    freopen("out.out", "w", stdout);
    #endif
        srand(time(NULL));
    //    cout << Miller_Rabin(1) << endl;
        while (scanf("%d", &n) != EOF) work();
        return 0;
    }
    View Code
  • 相关阅读:
    文件上传到服务器,写入文件和读取文件
    ajax
    jquery.gritter 提示
    lambda
    C# 对象初始化器和集合初始化器
    C# HttpHelper万能框架实现 接口
    插件总结
    backbone.js之Model篇 简单总结和深入(2)
    backBone.js初识
    利用 bugly 分析应用崩溃
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6721460.html
Copyright © 2011-2022 走看看