• Codeforces Round #565 (Div. 3)


    传送门

    A. Divide it!

    题意

      定义整数 n 上的三个操作:

      

      如果可以经过上述操作使得 n 变为 1,输出最小操作次数,反之,输出-1;

    题解

      易得 2 > 3/2 > 5/4;

      操作执行的优先级 1 > 2 > 3;

      按照优先级依次执行;

    AC代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 
     5 ll n;
     6 int Solve()
     7 {
     8     int ans=0;
     9     while(n%2 == 0)
    10     {
    11         n /= 2;
    12         ans++;
    13     }
    14     while(n%3 == 0)
    15     {
    16         n /= 3;
    17         ans += 2;
    18     }
    19     while(n%5 == 0)
    20     {
    21         n /= 5;
    22         ans += 3;
    23     }
    24     return n == 1 ? ans:-1;
    25 }
    26 int main()
    27 {
    28     int test;
    29     scanf("%d",&test);
    30     while(test--)
    31     {
    32         scanf("%lld",&n);
    33         printf("%d
    ",Solve());
    34     }
    35     return 0;
    36 }
    View Code

    B. Merge it!

    题意

      给你一个包含 n 个数的序列 a;

      定义序列 a 上的一个操作:合并任意两个元素;

      你可以对序列 a 执行上述操作任意次,求操作后的序列最多有多少元素可以被 3 整除;

    题解

      对于任意一个数 x ,如果 x 不是 3 的倍数,那么 x 最多加 2 就可以变成 3 的倍数;

      首先求出 ai 最少加多少可以变成 3 的倍数;

      共有三种可能:

        ①如果 ai%3 = 0,加0;

        ②ai%3 = 1,加2;

        ③ai%3 = 2,加1;

      ②和③结合正好是3的倍数,优先让②和③结合,剩余的自己结合;

    AC代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define INF 0x3f3f3f3f
     5 #define mem(a,b) memset(a,b,sizeof(a))
     6 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b);
     7 const int maxn=1e2+50;
     8 
     9 int n;
    10 int a[maxn];
    11 int b[3];
    12 
    13 int Solve()
    14 {
    15     b[0]=b[1]=b[2]=0;
    16     for(int i=1;i <= n;++i)
    17     {
    18         int k=a[i]%3;
    19         if(k == 0)
    20             b[0]++;
    21         else if(k == 1)
    22             b[2]++;
    23         else
    24             b[1]++;
    25     }
    26 
    27     return b[0]+min(b[1],b[2])+abs(b[2]-b[1])/3;
    28 }
    29 int main()
    30 {
    31 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    32     int test;
    33     scanf("%d",&test);
    34     while(test--)
    35     {
    36         scanf("%d",&n);
    37         for(int i=1;i <= n;++i)
    38             scanf("%d",a+i);
    39         printf("%d
    ",Solve());
    40     }
    41     return 0;
    42 }
    View Code

    C. Lose it!

    题意

      给你一个包含 n 个整数的序列 a;

      在删去 x 个数后,使得序列 a 可以划分成 (n-x) / 6 个 "good" 序列;

      求 x 的最小值;

    题解

      求出序列 a 最多有多少个 "good" 序列(假设有 ans 个),那么答案就是 n-6×ans;

    AC代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define INF 0x3f3f3f3f
     5 #define mem(a,b) memset(a,b,sizeof(a))
     6 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b);
     7 const int maxn=5e5+50;
     8 
     9 int n;
    10 int a[7]={0,4,8,15,16,23,42};
    11 map<int ,int >mymap;
    12 
    13 int b[7];///b[1]:4来到v[4][b[1]]位置,b[2,...,6]同理
    14 vector<int >v[7];///v[1]:存放4出现的所有位置,v[2,...,6]同理
    15 int ans;///"good"序列个数
    16 
    17 void DFS(int cur,int pre)
    18 {
    19     if(cur == 7)
    20     {
    21         ans++;
    22         return ;
    23     }
    24 
    25     ///找到上一个位置pre之后的最左的位置
    26     for(;b[cur] < v[cur].size() && v[cur][b[cur]] < pre;b[cur]++);
    27     if(b[cur] == v[cur].size())
    28         return ;
    29     ///查找下一个数的位置
    30     DFS(cur+1,v[cur][b[cur]++]);
    31 }
    32 int Solve()
    33 {
    34     ans=0;
    35     for(int i=0;i < v[1].size();++i)
    36         DFS(2,v[1][i]);///枚举4的每个位置
    37         
    38     return n-6*ans;
    39 }
    40 int main()
    41 {
    42 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    43     for(int i=1;i <= 6;++i)
    44         mymap[a[i]]=i;
    45         
    46     scanf("%d",&n);
    47     for(int i=1;i <= n;++i)
    48     {
    49         int x;
    50         scanf("%d",&x);
    51         v[mymap[x]].push_back(i);
    52     }
    53     printf("%d
    ",Solve());
    54     return 0;
    55 }
    View Code

    非DFS

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define memF(a,b,n) for(int i=0;i <= n;a[i++]=b);
     4 const int maxn=5e5+50;
     5 
     6 int n;
     7 int a[maxn];
     8 int num[10]={4,8,15,16,23,42};
     9 int b[50];
    10 vector<int >p[50];
    11 
    12 int Solve()
    13 {
    14     memF(b,0,49);
    15 
    16     int ans=0;///最多构成ans个"good"序列
    17     for(int i=0;i < p[4].size();++i)
    18     {
    19         int cur=p[4][i];
    20         for(int j=1;j <= 5;++j)
    21         {
    22             int index=num[j];
    23             for(;b[index] < p[index].size() && p[index][b[index]] <= cur;b[index]++);
    24             
    25             if(b[index] == p[index].size())
    26                 return n-6*ans;
    27 
    28             ///p[index]的b[index]位置已使用,所以b[index]++
    29             cur=p[index][b[index]++];
    30         }
    31         ans++;
    32     }
    33     return n-6*ans;
    34 }
    35 int main()
    36 {
    37     scanf("%d",&n);
    38     for(int i=1;i <= n;++i)
    39     {
    40         scanf("%d",a+i);
    41         p[a[i]].push_back(i);
    42     }
    43     printf("%d
    ",Solve());
    44 
    45     return 0;
    46 }
    View Code

    •二分

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define memF(a,b,n) for(int i=0;i <= n;a[i++]=b);
     4 const int maxn=5e5+50;
     5 
     6 int n;
     7 int a[maxn];
     8 int num[10]={4,8,15,16,23,42};
     9 vector<int >p[50];
    10 
    11 int Solve()
    12 {
    13     int ans=0;///最多构成ans个"good"序列
    14     for(int i=0;i < p[4].size();++i)
    15     {
    16         int cur=p[4][i];
    17         for(int j=1;j <= 5;++j)
    18         {
    19             int index=num[j];
    20             ///二分查找p[index]中 > cur 的位置
    21             vector<int >::iterator it=upper_bound(p[index].begin(),p[index].end(),cur);
    22             if(it == p[index].end())
    23                 return n-6*ans;
    24                 
    25             cur=*it;
    26             p[index].erase(it);///it位置已被使用,删掉
    27         }
    28         ans++;
    29     }
    30     return n-6*ans;
    31 }
    32 int main()
    33 {
    34     scanf("%d",&n);
    35     for(int i=1;i <= n;++i)
    36     {
    37         scanf("%d",a+i);
    38         p[a[i]].push_back(i);
    39     }
    40     printf("%d
    ",Solve());
    41 
    42     return 0;
    43 }
    View Code

    •效率比拼

      二分效率:

      

      非二分效率:

      

      总结:

      codeforces评测鸡是真的快呀;

     


    D. Recover it!

    •题意

      构造包含 n 个数的数组 a,使得 a 经过下述操作,多出 n 个数;

      这 2n 个数构成数组 b,即输入的 2n 个数;

      

      输出 a 数组中的 n 个数;

    •题解

      这 2n 个数要平分到两个集合 U,V 中;

      满足集合 U 通过上述两个操作可以推导出集合 V,并且是一一对应关系;

      那么,考虑一下这 2n 个数中的最大值 x 要归到哪个集合?

      ①x 为素数,x∈V;

      ②x 为合数,x∈U;

      根据这两个限定,首先将 b 排序,每次抽出最大值 x,判断 x 是否为素数;

      ①如果 x 为第 y 个素数,因为保证答案一定存在,那么 y 一定存在,并且 y 也是素数;

        将 x 归到集合 V,y 归到集合 U;

      ②如果 x 为合数,那么 x 归到集合 U,x的小于x的最大的约数 y 也一定存在,将 y 归到集合 V;

      最后输出集合 U 中的元素即可;

    Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mem(a,b) memset(a,b,sizeof(a))
     4 const int maxn=2e5+50;
     5 
     6 int n;
     7 int b[maxn<<1];
     8 map<int ,int >f;
     9 int cnt;
    10 int prime[maxn];
    11 bool isPrime[2750131+10];
    12 void Prime()
    13 {
    14     mem(isPrime,true);
    15     cnt=1;
    16     for(int i=2;cnt < (int)2e5;i++)
    17     {
    18         if(isPrime[i])
    19             prime[cnt++]=i;
    20         for(int j=1;j < cnt && prime[j]*i <= 2750131;++j)
    21         {
    22             isPrime[prime[j]*i]=false;
    23             if(i%prime[j] == 0)
    24                 break;
    25         }
    26     }
    27 }
    28 
    29 void Solve()
    30 {
    31     sort(b+1,b+2*n+1);
    32     for(int i=2*n;i >= 1;--i)
    33     {
    34         int x=b[i];
    35         if(f[x] == 0)
    36             continue;
    37 
    38         int y=lower_bound(prime+1,prime+cnt,x)-prime;
    39         if(y < cnt && prime[y] == x)
    40         {
    41             printf("%d ",y);
    42             f[x]--;
    43             f[y]--;
    44         }
    45         else
    46         {
    47             for(int i=2;;i++)
    48                 if(x%i == 0)
    49                 {
    50                     y=x/i;
    51                     break;
    52                 }
    53             printf("%d ",x);
    54             f[x]--;
    55             f[y]--;
    56         }
    57     }
    58     printf("
    ");
    59 }
    60 int main()
    61 {
    62     Prime();
    63 
    64     scanf("%d",&n);
    65     f.clear();
    66     for(int i=1;i <= 2*n;++i)
    67     {
    68         scanf("%d",b+i);
    69         f[b[i]]++;
    70     }
    71     Solve();
    72 
    73     return 0;
    74 }
    View Code

    E. Cover it!

    题意

      从含有 n 个点,m 条边的无向图中取出 x 个点,这 x 个点需满足:

      ① x ≤ n/2;

      ②剩余的点至少与这 x 个点中的一个点有连边;

      输出满足条件的这 x 个点;

    题解

    二部图裸题;

      找出集合 U 和集合 V,输出 |U| 和 |V| 中元素个数最少的集合;

    AC代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define INF 0x3f3f3f3f
     5 #define mem(a,b) memset(a,b,sizeof(a))
     6 #define memF(a,b,n) for(int i=0;i<=n;a[i++]=b);
     7 const int maxn=2e5+50;
     8 
     9 int t;
    10 int n,m;
    11 int num;
    12 int head[maxn];
    13 struct Edge
    14 {
    15     int to,next;
    16 }G[maxn<<1];
    17 void addEdge(int u,int v)
    18 {
    19     G[num]=Edge{v,head[u]};
    20     head[u]=num++;
    21 }
    22 int col[maxn];///col[i]:节点i所属的集合
    23 
    24 ///集合U中的元素染成0
    25 ///集合V中的元素染成1
    26 void DFS(int u,int k)
    27 {
    28     col[u]=k;
    29 //    printf("u=%d,k=%d
    ",u,k);
    30     for(int i=head[u];~i;i=G[i].next)
    31     {
    32         int v=G[i].to;
    33         if(col[v] != -1)
    34             continue;
    35         DFS(v,k^1);
    36     }
    37 }
    38 void Solve()
    39 {
    40     memF(col,-1,n);
    41     DFS(1,0);
    42     int a=0,b=0;
    43     for(int i=1;i <= n;++i)
    44         if(col[i])
    45             a++;
    46         else
    47             b++;
    48             
    49     int ans=a > b ? 0:1;
    50     printf("%d
    ",min(a,b));
    51     for(int i=1;i <= n;++i)
    52         if(col[i] == ans)
    53             printf("%d ",i);
    54     printf("
    ");
    55 }
    56 void Init()
    57 {
    58     num=0;
    59     memF(head,-1,n);
    60 }
    61 int main()
    62 {
    63 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    64     int test;
    65     scanf("%d",&test);
    66     while(test--)
    67     {
    68         scanf("%d%d",&n,&m);
    69         Init();
    70         for(int i=1;i <= m;++i)
    71         {
    72             int u,v;
    73             scanf("%d%d",&u,&v);
    74             addEdge(u,v);
    75             addEdge(v,u);
    76         }
    77         Solve();
    78     }
    79     return 0;
    80 }
    View Code
  • 相关阅读:
    错误提示窗口-“操作系统当前的配置不能运行此应用程序”
    打印机无法打印的10种解决方法
    开发进度三
    人月神话阅读笔记二
    开发进度二
    开发进度1
    人月神话阅读笔记一
    库存物资管理系统
    四则运算
    动手动脑5
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10995733.html
Copyright © 2020-2023  润新知