Codeforces Round #611 (Div. 3)
F
题意:给你n-1边,n个灯,每个边连着两颗灯,有主,次灯区别,电流由主到次,每条边有一个特性,取消这条边后n个灯不能亮的值(每个灯亮值为2^i,灯编号i),由特性值由大到小给出每条边的主灯,求出每对主灯次灯。
题解:可知是一棵树,排第一个的肯定是原点,即根。然后没出现的肯定是叶子节点,我们遍历一遍求出叶子节点,然后我们知道灯亮与编号有关,所以我们由将叶子节点放入优先队列,叶子节点从小到大与主灯从小到大匹配,当主灯中的cnt【i】为0,说明他已经没有子树,也就是他也是一颗“叶子节点了”
就放入优先队列中继续匹配。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; priority_queue<int,vector<int>,greater<int> >pq; int k,n,x[maxn],vis[maxn],cnt[maxn]; vector<pair<int,int> >G; int main() { cin>>n; int tot=n-1; for(int i=1;i<n;i++){ cin>>x[i]; vis[x[i]]=1; cnt[x[i]]++; } printf("%d\n",x[1]); for(int i=1;i<=n;i++){ if(!vis[i]) pq.push(i); } while(1){ if(tot==0) break; int now=pq.top();pq.pop(); int res=x[tot];tot--; G.push_back(make_pair(res,now)); cnt[res]--; if(cnt[res]==0) pq.push(res); } int sz=G.size(); for(int i=0;i<sz;i++){ printf("%d %d\n",G[i].first,G[i].second); } }
E
题意:每个人可以出现三个操作,将自己呆在原地,或向右移动一距离或向左。
求最大占用地方块数和最小的占用地方块数。
分析:最多就是尽可能得让所有房子都有人嘛,最少就是尽可能得集中这些人。 代码: #include<bits/stdc++.h> using namespace std; const int maxn=2e5+7; int x[maxn],n,xx,xxx[maxn]; int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> xx, x[xx]++, xxx[xx]++; for (int i = n + 1; i >= 1; i--) { if (x[i] > 1) { x[i - 1]++; x[i]--; } } for (int i = 0; i <= n; i++) { if (x[i] > 1) { x[i + 1]++; x[i]--; } } int most = 0; for (int i = 0; i <= n + 1; i++) { if (x[i]) most++; } int least = 0; for (int i = 1; i <= n + 1;) { if (xxx[i]) { i += 3; least++; } else { i++; } } cout << least << " " << most << endl; return 0; }
D.Christmas Trees
题目大意:给定n个不同的整数点,让你找m个不同的整数点,使得这m个点到到这n个点最小距离之和最小。
分析:对于每个点,肯定是先选取距离为1的,然后再选取距离为2的,以此类推。但是有的点不一定选得到,因此我们可以用队列来存储那些可以到达的点,这样就可以得知这个题跑个bfs可行。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+10; int n,m,a[maxn]; vector<int>G; ll ans; map<int,bool>vis; struct node { int pos,len; }; queue<node>q; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); vis[a[i]]=1; } for(int i=1;i<=n;i++){ if(vis[a[i]-1]==0) q.push(node{a[i]-1,1}),vis[a[i]-1]=1; if(vis[a[i]+1]==0) q.push(node{a[i]+1,1}),vis[a[i]+1]=1; } while(m--){ node res=q.front();q.pop(); int u=res.pos,v=res.len; G.push_back(u); ans+=v; if(vis[u-1]==0){ q.push(node{u-1,v+1}); vis[u-1]=1; } if(vis[u+1]==0){ q.push(node{u+1,v+1}); vis[u+1]=1; } } printf("%lld\n",ans); int sz=G.size(); for(int i=0;i<sz;i++){ if(i)printf(" %d",G[i]); else printf("%d",G[i]); } puts(""); return 0; }
题目大意:每个人都要给其他一个人一个礼物,并且每个人都要收到一个礼物。请你构造一种合法的赠送礼物的方法,使得每个人都赠送非自己的人一个礼物,并且从其他人那里收到一个礼物。
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef vector<int> VI; typedef vector<VI> VII; typedef vector<VII> VIII; typedef pair<int, int> PII; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) const int N = 2e5 + 5; const ll MOD = 1e9 + 7; int flag[N]; int give[N]; int gett[N]; queue<int> Q; int num = 0; int main() { int n; scanf("%d", &n); rep(i,1,n) { int x; scanf("%d", &x); flag[i] = x; give[i] = x; if(x != 0) gett[x] = i; else num ++; } rep(i,1,n) { if(gett[i] == 0) Q.push(i); } int pos = 1; rep(i,1,n) { if(give[i] == 0) { pos = i; while(give[pos] == 0) { give[pos] = Q.front(); Q.pop(); if(pos == give[pos]) { Q.push(pos); give[pos] = Q.front(); Q.pop(); } pos = give[pos]; num --; } } } rep(i,1,n) { if(give[i] == i) { rep(j,1,n) { if(flag[j] == 0) { swap(give[i], give[j]); break; } } } } rep(i,1,n) { printf("%d ", give[i]); } printf("\n"); return 0; }