标签: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