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; }