• CF449C:Jzzhu and Apples


    题意简述

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

    很妙的一道题。

    首先我们考虑去处理每个质数的倍数,那么这个质数一定是小于等于 n/2 的,不然它在 n 的范围内是不会有倍数的。

    那么我们先把 $1~n/2$ 范围内的所有质数筛出来。

    枚举质数

    然后我们要怎么用质数去处理答案呢?

    首先我们从大到小枚举这些质数,然后去枚举它的倍数。

    然鹅这样复杂度不会炸么?不会。 $O(sigma_{i=2}^{n/2}n/i)$ 的复杂度吧,而且还远达不到。

    信仰一下应该是过得了的,实际上确实也过了。

    处理倍数

    然后我们再考虑如果这些倍数该怎么处理。

    我们首先看这些倍数有没有被使用过,没有的话就入栈。

    最优性理解

    那么为什么能用就入栈的解法最优呢?

    其实很简单,因为当前枚举那个数可以被当前的质数整除,那么该数与当前枚举质数的倍数去匹配肯定不会产生更劣的结果。

    那么如果有数字剩下来呢?

    如果说当前枚举质数的未使用过的倍数有奇数个,那么我们可以将第 2 个倍数与最后一个换一下,然后弹出栈,标记为未使用。

    为什么这样做能达到最优?

    考虑第二个倍数一定是 2 的倍数,那么把他弹出的话就可以和 2 的倍数去匹配,而且我们每次遇到奇数个的情况都是弹 2 的倍数,那么这些多余的数就可以凑一块儿了。

     1 //by Judge
     2 #include<vector>
     3 #include<cstdio>
     4 #include<iostream>
     5 #define P make_pair
     6 using namespace std;
     7 const int M=1e5+11;
     8 char sr[1<<21],z[20];int C=-1,Z;
     9 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    10 inline void print(int x,char chr='
    '){
    11     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    12     while(z[++Z]=x%10+48,x/=10);
    13     while(sr[++C]=z[Z],--Z);sr[++C]=chr;
    14 } int n,cnt,ans,top,prim[M],is[M],vis[M],num[M];
    15 pair<int,int> tmp[M];
    16 inline void prep(){
    17     for(int i=2;i<=n>>1;++i){
    18         if(!is[i]) prim[++cnt]=i;
    19         for(int j=1;j<=cnt&&i*prim[j]<=n/2;++j){
    20             is[i*prim[j]]|=1;
    21             if(i%prim[j]==0) break;
    22         }
    23     }
    24 }
    25 int main(){
    26     scanf("%d",&n),prep();
    27     for(int i=cnt;i;--i){ top=0;
    28         for(int j=prim[i];j<=n;j+=prim[i])
    29             if(!vis[j]) num[++top]=j,vis[j]|=1;
    30         if(top&1) swap(num[2],num[top]),vis[num[top]]=0,--top;
    31         for(int j=1;j<=top;j+=2) tmp[++ans]=P(num[j],num[j+1]);
    32     } print(ans);
    33     for(int i=1;i<=ans;++i)
    34         print(tmp[i].first,' '),
    35         print(tmp[i].second);
    36     return Ot(),0;
    37 }
  • 相关阅读:
    如何启动SOLR特性: 按层面检索
    solr的范围查询 TO
    jetty
    solr高亮的使用
    SQL日期加一天
    SQL从第二条开始取记录
    写出昨天的日期
    SQL取前后一条数据
    项目组【网站】的项目
    获取input文本框中高亮显示的值
  • 原文地址:https://www.cnblogs.com/Judge/p/9859989.html
Copyright © 2020-2023  润新知