CF449C Jzzhu and Apples

题意

给出正整数n,你要把1-n之间的正整数分成尽可能多组,使得每一组两个数的最大公约数大于1;输出能分成最多组的个数,并按任意顺序输出每组的两个数.

考虑约数最大化利用(或者是尽量用上较大的素数)

发现n/2以上的素数没有用 考虑n/2以下的素数

从大往小尽量找自己的倍数

不明白可以想一下 拿一个大偶数去匹配2 和拿4匹配2 哪一个更划算

然后如果有奇数个倍数就拿出去匹配最小的质数

也就是把2倍拿出去与其他偶数匹配

复杂度 遍历所有因子应该是O(nlgn) (反正O(nsqrt(n))也能过)

Time cost:75min

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define ms(a,b) memset(a,b,sizeof a)
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define inf 2147483647
using namespace std;
typedef long long ll;
ll read() {
    ll as = 0,fu = 1;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') fu = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        as = as * 10 + c - '0';
        c = getchar();
    }
    return as * fu;
}
const int N = 1000005;
//head
int n;
vector<int> v;
int mindiv[N],prim[N],top;
void initprim(int n) {
    rep(i,2,n) {
    if(!mindiv[i]) prim[++top] = i;
    for(int j = 1;j <= top && prim[j] * i <= n;j++) {
        mindiv[i * prim[j]] = prim[j];
        if(i % prim[j] == 0) break;
    }
    }
}
bool vis[N];
pair<int,int> tmp[N];
int ans;
int main() {
    scanf("%d",&n);
    initprim(n>>1);
    per(i,top,1) {
    v.clear();
    for(int j = prim[i];j <= n;j += prim[i]) {
        if(!vis[j]) v.push_back(j);
        vis[j] = 1;
    }
    int sze = v.size();
    if(sze & 1) sze--,swap(v[1],v[sze]),vis[v[sze]] = 0;
    for(int j = 0;j < sze;j += 2) {
        tmp[++ans] = make_pair(v[j],v[j+1]);
    }
    }
    printf("%d
",ans);
    rep(i,1,ans) printf("%d %d
",tmp[i].first,tmp[i].second);
    return 0;
}
> 别忘了 总有人在等着你
原文地址:https://www.cnblogs.com/yuyanjiaB/p/9778843.html