CF449C Jzzhu and Apples

传送门

这道题好像一开始想到了差不多的做法orz?后来都不大敢相信就是这么做的……有点瞎搞。

后来看了CF的官方题解,感觉还是挺有道理的。首先对于1和大于n/2的质数肯定是不行的,我们直接忽略。然后,对于每一个质数的倍数,我们肯定是把他们组合在一起更优。如果这些数有奇数个,那我们就把质数的2倍挑出来(因为2倍是最容易组合的!)

如果有偶数个就直接组合。

最后你肯定剩下的全都是偶数,那么随便组合就行啦!

直接用两个栈模拟即可。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
#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 enter putchar('
')

using namespace std;
typedef long long ll;
const int M = 200005;
const int INF = 1000000009;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

int n,p[M],stack[M],tot,cur,sta[M],cnt,now;
bool np[M],vis[M];
pr ans[M];

void euler()
{
    np[1] = 1;
    rep(i,2,n)
    {
    if(!np[i]) p[++tot] = i;
    for(int j = 1;i * p[j] <= n;j++)
    {
        np[i*p[j]] = 1;
        if(!(i%p[j])) break;
    }
    }
}

int main()
{
    n = read();
    euler();
    rep(i,2,tot)
    {
    if(p[i] > n>>1) break;
    rep(j,1,n/p[i]) if(j != 2 && !vis[p[i] * j]) sta[++cur] = p[i] * j,vis[p[i] * j] = 1;
    if(cur&1)
    {
        sta[++cur] = p[i] << 1,vis[p[i] << 1] = 1;
        while(cur) ans[++cnt].fi = sta[cur--],ans[cnt].sc = sta[cur--];
    }
    else
    {
        stack[++now] = p[i] << 1,vis[p[i] << 1] = 1;
        while(cur) ans[++cnt].fi = sta[cur--],ans[cnt].sc = sta[cur--];
    }
    }
    rep(j,1,n>>1) if(!vis[j<<1]) stack[++now] = j << 1;
    if(now&1) now--;
    while(now) ans[++cnt].fi = stack[now--],ans[cnt].sc = stack[now--];
    printf("%d
",cnt);
    rep(i,1,cnt) printf("%d %d
",ans[i].fi,ans[i].sc);
    return 0;
}
原文地址:https://www.cnblogs.com/captain1/p/9781303.html