码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #615 (Div. 3) A-F简要题解

时间:2020-01-28 09:16:10      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:tree   需要   贪心   ||   次数   不同的   front   can   增加   

contest链接:https://codeforces.com/contest/1294

 

A.

给出a、b、c三个数,从n中分配给a、b、c,问能否使得a = b = c。计算a,b,c三个数的差值之和,n对其取余,判断是否为0即可。

AC代码:

 1     #include<iostream>
 2     #include<vector>
 3     #include<algorithm>
 4     #include<cmath>
 5     #include<cstring>
 6     #include<queue>
 7     #include<cstdio>
 8     #include<stack>
 9     #include<unordered_map>
10     #define inf 0x3f3f3f3f
11     using namespace std;
12     typedef long long ll;
13     int main(){
14         int t;
15         scanf("%d",&t);
16         while(t--){
17             int n,a,b,c;
18             scanf("%d%d%d%d",&a,&b,&c,&n);
19             if(a<b) swap(a,b);
20             if(a<c) swap(a,c);
21             if(b<c) swap(b,c);
22             int dif = a - b + a - c;
23             if((n - dif)%3 == 0 && (n - dif)>=0) printf("YES\n");
24             else printf("NO\n");
25             
26         }
27         return 0;
28     }

 

B. Collecting Packages

题意:给定一些点的坐标,问从起点开始移动,能否经过所有的点,且每次只能向上向右移动,求出路径。

思路:所有点按横纵坐标排序,扫一遍所有的点,每次先向右再向上走。

 1  
 2     #include<iostream>
 3     #include<vector>
 4     #include<algorithm>
 5     #include<cmath>
 6     #include<cstring>
 7     #include<queue>
 8     #include<cstdio>
 9     #include<stack>
10     #include<unordered_map>
11     #define inf 0x3f3f3f3f
12     using namespace std;
13     typedef long long ll;
14     const int maxn = 1005;
15     struct node{
16         int x,y;
17     };
18     bool cmp(node a,node b){
19         if(a.x == b.x ) return a.y < b.y ;
20         return a.x < b.x ;
21     }
22     int main(){
23         int t;
24         scanf("%d",&t);
25         while(t--){
26             int n;
27             scanf("%d",&n);
28             node g[maxn];
29             for(int i = 1;i<=n;i++) {
30                 scanf("%d%d",&g[i].x,&g[i].y);
31             }
32             sort(g+1,g+1+n,cmp);
33             string ans = "";
34             int f = 1;
35             int curx = 0,cury = 0;
36             for(int i = 1;i<=n;i++){
37                 if(i == 1){
38                     int lenR = g[i].x - curx;
39                     int lenU = g[i].y - cury;
40                     ans.append(lenR,R); 
41                     ans.append(lenU,U); 
42                     curx = g[i].x ,cury = g[i].y ;
43                 }
44                 else{
45                     if(g[i].x < curx || g[i].y < cury){
46                         cout<<"NO"<<endl;
47                         f = 0;
48                         break;
49                     }
50                     int lenR = g[i].x - curx;
51                     int lenU = g[i].y - cury;
52                     ans.append(lenR,R); 
53                     ans.append(lenU,U);     
54                     curx = g[i].x ,cury = g[i].y ;
55                 }
56             }
57             if(f == 0) continue;
58             cout<<"YES"<<endl;
59             cout<<ans<<endl;
60         }
61         return 0;
62     }

 

C. Product of Three Numbers

题意:求不同的三个数a、b、c,使得a*b*c = n

思路:自己的做法有点复杂,用唯一分解定理做,枚举n的质因子,用质因子去组合成a,b,c,最后判断。

 1 #include<iostream>
 2 #include<vector>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<queue>
 7 #include<cstdio>
 8 #include<map>
 9 #include<set>
10 #include<stack>
11 #include<unordered_map>
12 #define inf 0x3f3f3f3f
13 using namespace std;
14 typedef long long ll;
15 void solve(){
16     int n;
17     cin>>n;
18     int tn = n;
19     set<int> s;
20     int a,b;
21     int t = 1;
22     for(int i = 2;i*i<=n;i++){
23         while(n%i == 0){//枚举质因子
24             n/=i;
25             t = t*i;
26             if(s.count(i) == 0 ){
27                 s.insert(i);
28                 t = 1;
29             }
30             if(s.count(t) == 0 && t!=1){
31                 s.insert(t);
32                 t = 1;
33             }
34             if(s.size() == 2){
35                 set<int>::iterator iter = s.begin();
36                 int x=*iter;
37                 iter++;
38                 x*=*iter;
39                 if(s.count(tn/x) == 0 && tn/x!=1) {
40                     s.insert(tn/x);
41                     break;
42                 }
43             
44             }
45             if(s.size()>=3) {
46                 break;
47             }
48         }
49         if(s.size()>=3) break;
50     }
51     if(s.size()>=3){
52         cout<<"YES"<<endl;
53         set<int>::iterator iter = s.begin();
54         while(iter!=s.end()){
55             cout<<*iter<<" ";
56             iter++;
57         }
58     }
59     else{
60         cout<<"NO"<<endl;
61     }
62 }
63 int main(){
64     int t;
65     cin>>t;
66     while(t--){
67         solve();
68     }
69     return 0;
70 }

 

D. MEX maximizing

题意:一个空数组,一个x值,有q次询问,每次询问向数组插入一个值,数组中所有的值可以任意增加n*x倍,减少n*x被,每次询问输出不包含在数组中最小的正整数值。

思路:一道思维题。每次询问时,把插入的值对x取余,设其为y,意为x可以转移成y,每次记录可以转移到y的数字个数,每次需要y时就查询,这样贪心地进行下去即可,时间复杂度O(n)级别。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 4e5+5;
 4 int v[maxn];
 5 int q,x;
 6 int main(){
 7     scanf("%d%d",&q,&x);
 8     int mex = 0;
 9     while(q--){
10         int y;scanf("%d",&y);
11         if((y%x)!=(mex%x)) v[y%x]++;//当前如果不需要 就先记录下来(y%x)的个数
12         else{
13             mex++;//否则就消耗掉
14             while(1){
15                 if(v[mex%x]) v[mex%x]--,mex++;//查询目前所需要的,如果有就消耗一次,再令mex++
16                 else break;
17             }
18         }
19         printf("%d\n",mex);
20     }
21     return 0;
22 }

 

E. Obtain a Permutation

题意:一个n×m的矩阵,矩阵元素的总个数不会超过2e5,有两种操作,1.改变矩阵中任意一元素的值 2.令矩阵的一列所有元素向上移动一格。 求矩阵所有元素恢复成最初位置所需要的最少操作次数

思路:操作只与列有关,贪心地去枚举每一列。扫描一列地的元素,开一个cnt数组,首先判断一下这个元素是否属于该列,如果属于该列,那么记录他恢复到原有位置需要向上移动多少次,假设需要i次,那么让cnt[i] ++,这样扫描完一列之后,再去找该列恢复原有序列的最小操作次数,ans = min(ans,i+n-cnt[i] ),i是该列所有元素移动次数,n是该列元素的个数,n-cnt[i]就是通过向上移动i次,不能到原有位置的元素,这样只能用操作1来实现了。

 1 #include<bits/stdc++.h>
 2 #define inf 0x3f3f3f3f
 3 using namespace std;
 4 int n,m;
 5 int main(){
 6     scanf("%d%d",&n,&m);
 7     int g[n][m];
 8     for(int i = 0;i<n;i++){
 9         for(int j = 0;j<m;j++){
10             scanf("%d",&g[i][j]);
11         }
12     }
13     int ans = 0;
14     for(int i = 0;i<m;i++){
15         vector<int> cnt(n);
16         for(int j = 0;j<n;j++) cnt[j] = 0;//初始化cnt数组
17         for(int j = 0;j<n;j++){
18             if((g[j][i]-1)%m == i && g[j][i]<=m*n){//如果该元素属于这一列
19                 int h = (g[j][i]-1)/m ;//计算原有的位置
20                 int dif = j - h;//计算需要向上移动的次数
21                 if(dif<0) dif+=n;
22                 cnt[dif]++;//记录+1
23             }
24         }
25         int t = inf;
26         for(int j = 0;j<n;j++) t = min(t,j+n-cnt[j]);//找出该列元素回到原有位置需要的最少操作次数
27         ans+=t;//每一列操作次数都加和
28     }
29     printf("%d",ans);
30     return 0;
31 }

 

F. Three Paths on a Tree

题意:给出一无权棵树,在树中找到三个结点a,b,c使得a到b到c路径距离最长,如果a到b的路径和a到c的路径有重复,重复的部分不做计算。

思路:首先树中两点之间最远的距离是树的直径,那么可以用bfs求出树的直径,直径两个端点设为a和b,再用bfs求出其他点到a和b的距离,最后枚举c点即可,这样是最优的,最终答案就等于(dis_ab+dis_bc+dis_ac) / 2。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e5+5;
 4 vector<int> G[maxn];
 5 int dis1[maxn],dis2[maxn],dis[maxn],v[maxn];
 6 int n,a,b,c,pos,disab,disac,disbc; 
 7 void bfs(int cur){
 8     queue<int> q;
 9     q.push(cur);
10     memset(v,0,sizeof(v));
11     memset(dis,0,sizeof(dis));
12     v[cur] = 1;
13     int p = cur,temp = 0;
14     while(!q.empty()){
15         int now = q.front();
16         q.pop();
17         for(int i = 0;i<G[now].size();i++){
18             if(v[G[now][i]] == 0){
19                 v[G[now][i]] = 1;
20                 q.push(G[now][i]);
21                 dis[G[now][i]] = dis[now] + 1;//计算距离
22                 if(dis[G[now][i]] > temp) p = G[now][i],temp = dis[G[now][i]];
23             }
24         }
25     }
26     pos = p;
27 }
28 
29 int main(){
30     scanf("%d",&n);
31     int st;
32     for(int i = 0;i<n-1;i++){
33         int u,v;
34         scanf("%d%d",&u,&v);
35         st = u;
36         G[u].push_back(v),G[v].push_back(u);
37     }
38     bfs(1);//枚举a
39     a = pos ;
40     bfs(a);//枚举b
41     b = pos;
42     int t = 0;//两边bfs求出树的直径
43     for(int i = 1;i<maxn;i++){//求出其他点到a的距离
44         dis1[i] = dis[i];
45         if(dis1[i]>t) {
46             b = i,t = dis1[i],disab = dis1[i];
47         }
48     } 
49     bfs(b);
50     t = 0;
51     for(int i = 1;i<maxn;i++){//求出其他点到b的距离
52         dis2[i] = dis[i];
53         if(dis1[i]>t) {
54             t = dis2[i];
55         }
56     }
57     for(int i = 1;i<maxn;i++){
58         if(dis1[i]+dis2[i] > disac + disbc && i!=a && i!=b){//枚举c点
59             disac = dis1[i],disbc = dis2[i];
60             c = i;
61         }
62     } 
63     printf("%d\n",(disac+disab+disbc)/2);
64     printf("%d %d %d",a,b,c);
65     return 0;
66 }

 

Codeforces Round #615 (Div. 3) A-F简要题解

标签:tree   需要   贪心   ||   次数   不同的   front   can   增加   

原文地址:https://www.cnblogs.com/AaronChang/p/12237306.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!