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\n",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\n",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\n",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\n",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\n",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("\n");
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\n",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\n",min(a,b));
51     for(int i=1;i <= n;++i)
52         if(col[i] == ans)
53             printf("%d ",i);
54     printf("\n");
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

 

posted @ 2019-06-10 07:31  HHHyacinth  阅读(313)  评论(0编辑  收藏  举报