2020牛客暑期多校训练营(第四场)H Harder Gcd Problem 题解(贪心)

题目链接

CF原题

题目大意

有N个苹果,编号为1~N。现要将苹果组成若干对,每对苹果最小公约数不为1。求最多能分成多少对,输出各对的组成。

题目思路

其实就是从后往前进行贪心匹配,枚举每一个质因子,计算包含这个质因子的数量。如果是偶数的话,那么就直接全部计算,如果是奇数的话,那么就留下2p,显然是可以留下2p的,因为2*p就只有两个质因子,不可能在此前被匹配到,也能最后在被2匹配。

CF标称:
Firstly, we should notice that 1 and the primes larger than N / 2 can not be matched anyway, so we ignore these numbers.

Let’s consider each prime P where 2 < P ≤ N / 2. For each prime P, we find all of the numbers which are unmatched and have a divisor P. Let M be the count of those numbers we found. If M is even, then we can match those numbers perfectly. Otherwise, we throw the number 2P and the remaining numbers can be matched perfectly.

Finally, only even numbers may be unmatched and we can match them in any way.

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define debug printf("I am here\n");
using namespace std;
typedef long long ll;
const int maxn=2e5+5,mod=2147493647,inf=0x3f3f3f3f;
const double eps=1e-10;
int t,n,prime[maxn];
bool vis[maxn];
vector<pair<int,int> > ans;
vector<int> vec;
void getprime(){
    for(ll i=2;i*i<=2e5;i++){
        if(!prime[i]){
            for(ll j=i*i;j<=2e5;j+=i){
                prime[j]=1;
            }
        }
    }
}
void init(){
    ans.clear();
    for(int i=1;i<=n;i++){
        vis[i]=0;
    }
}
int main(){
    getprime();
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        init();
        for(int i=n/2;i>=2;i--){
            if(prime[i]) continue;//合数直接 continue
            int cnt=0,beg;
            vec.clear();
            for(int j=i;j<=n;j+=i){
                if(!vis[j]){
                    vis[j]=1;
                    cnt++;
                    vec.push_back(j);
                }
            }
            if(cnt%2){
                vis[2*i]=0;
                ans.push_back({vec[0],vec[2]});
                //这里我本来写的是i,3*i但是3*i可能已经被筛了
                beg=3;
            }else{
                ans.push_back({i,2*i});
                beg=2;
            }
            for(int j=beg;j+1<(int)vec.size();j+=2){
                ans.push_back({vec[j],vec[j+1]});
            }
        }
        printf("%d\n",(int)ans.size());
        for(int i=0;i<(int)ans.size();i++){
            printf("%d %d\n",ans[i].fi,ans[i].se);
        }
    }
    return 0;
}

你可能感兴趣的:(贪心)