Harder Gcd Problem(素数筛,贪心)

题目:就是给你1到n这你个数,从中能找出的两个数gcd>1且不重复的最大对数,并打印出来。
思路:因为是gcd>1很容易就能想到是每个搭配都一定是质数与其倍数或质数不同倍数之间的搭配。进而就可以得出一个大于n/2的质数在n中一定不存在搭配(因为乘以2就大于n了),对于剩下不大于n/2的质数采取的贪心策略应该是从大到小进行匹配,因为越大的质数,合适的匹配越少,如果质数从小到大匹配就可能出现小的质数匹配了大的质数的倍数就会导致大的质数匹配减少而漏算(比如:1到15,如果3和15先匹配5就没有匹配的了,但5和15匹配了,3还可以和9进行匹配),如果一个质数加上其倍数一共有偶数个当然就可以两两一组直接完美匹配,如果是奇数个我们可以考虑将该质数的2倍先筛除(因为质数最小是2 最差的结果也只是2的倍数是奇数至多只筛除一个数),再把剩下的偶数个数两两匹配即可。
ac代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define int long long
const int maxn = 2e5 + 5;
int prime[maxn];
int vis[maxn],cnt;
int lll[maxn];
int ans[maxn], ans2[maxn];
void init() {//欧拉筛(埃氏筛应该也行,看见有dalao用埃氏筛过了)
    for (int i = 2; i <= 1e5; i++) {
        if (vis[i] == 0) prime[++cnt] = i;
        for (int j = 1; j <= cnt && prime[j] * i <= 1e5; j++) {
            vis[prime[j] * i] = 1;
            if (i % prime[j] == 0) break;
        }
    }
}
signed main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t; cin >> t;
    init();
    while (t--) {
        int a; cin >> a;
        int k = a / 2;
        int f = upper_bound(prime + 1, prime + 1 + min(cnt, k), k) - prime - 1;//寻找不大于n/2的最大质数
        memset(vis, 0, sizeof(vis)); int m = 0;
        for (int i = f; i >= 1; i--) {
            int res = 0;
            lll[++res] = prime[i];
            for (int j = 2; j * prime[i] <= a; j++) {
                int ll = j * prime[i];
                if (!vis[ll]) lll[++res] = ll;
            }
            if (res % 2 == 0) {
                for (int i = 1; i <= res; i += 2) {
                    ans[++m] = lll[i]; ans2[m] = lll[i + 1];
                    vis[lll[i]] = 1; vis[lll[i + 1]] = 1;
                }
            }
            else {
                ans[++m] = lll[1]; ans2[m] = lll[3];
                for (int i = 4; i <= res; i += 2) {
                    ans[++m] = lll[i]; ans2[m] = lll[i + 1];
                    vis[lll[i]] = 1; vis[lll[i + 1]] = 1;
                }
            }
        }
        cout << m << endl;
        for (int i = 1; i <= m; i++) cout << ans[i] << " " << ans2[i] << endl;
    }
    return 0;
}

你可能感兴趣的:(Harder Gcd Problem(素数筛,贪心))