CF#163(div 3)
QAQ:本来打算打的,后来一想快一个月没碰算法了,还是算了,于是乎晚上没打,第二天开了重现,最终A掉了两道题,死在了C题上了,到最后也没发现写的有什么问题,cf上的题解给出的思路跟我的不一样,所以也没找出来错在哪了,但是cf上的思路更加巧妙,本篇题解就用cf上的思路了
A. Minutes Before the New Year
简单模拟题,水题
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; while(T--) { int h ,m; cin >> h >> m; cout << (23-h)*60+(60-m) << endl; } return 0; }
B. Candies Division
根据题意,最终输出结果可以由两部分构成,一部分是均分,即n/k*k,另一部分就是n%k,根据条件,另一部分应该是min(n%k,k/2)。两者相加即是结果。
#include <bits/stdc++.h> using namespace std; typedef long long LL; int main() { int T; cin >>T; while(T--) { LL n,k; cin >> n >> k; LL ans = 0; ans = (n/k)*k+min(n%k,k/2); cout << ans << endl; } return 0; }
C. Friends and Gifts
这个题需要用转化为图论来解决,在输入中有三种特殊节点,一为入度为零的结点,即没有人给他送礼物,但他有想送礼物给了别人,二为出度为零的结点,即有人给他送礼物,但他没有想送出礼物的人,三为入度和出度都为零的结点,这种结点是图中的的孤立结点。
我们先处理第三种节点,如果这种节点的数目大于1,那我们就可以让他们自己构成一个环,如果只有一个这种节点,我们可以在图中找一个未成环的链的链首,也就是第一种结点,让孤立结点指向这个结点,然后更新一下这两个节点的出度以及入度。
然后从所有节点中提取出第一种结点和第二种结点,按照题意,这两种节点的数目一定是相等的。然后相应匹配连接即可。
#include <bits/stdc++.h> using namespace std; int main() { int n; cin >> n; vector<int> f(n); vector<int> in(n),out(n); for(int i = 0;i<n;++i) { cin >>f[i]; --f[i]; if(f[i]!=-1){ ++out[i]; ++in[f[i]]; } } vector<int> loops; for(int i =0;i<n;++i){ if(in[i]==0&&out[i]==0) { loops.push_back(i); } } if(loops.size()==1) { int idx = loops[0]; for(int i = 0;i<n;++i){ if(in[i]==0&&i!=idx) { f[idx] = i; ++out[idx]; ++in[i]; break; } } } else if(loops.size()>1) { for(int i = 0;i<loops.size();++i){ int cur = loops[i]; int nxt = loops[(i+1)%(int)loops.size()]; f[cur] = nxt; ++out[cur]; ++in[cur]; } } loops.clear(); vector<int> ins, outs; for(int i = 0;i<n;++i){ if(in[i]==0) ins.push_back(i); if(out[i]==0) outs.push_back(i); } // assert(ins.size()==outs.size()); for(int i = 0;i<int(outs.size());++i) { f[outs[i]] = ins[i]; } for(int i = 0;i<n;++i){ cout << f[i]+1 << " "; } cout <<endl; return 0; }
D. Christmas Trees
多元BFS
#include <bits/stdc++.h> using namespace std; set<int>s; typedef long long LL; struct Node { int id; LL dis; Node(int _id = 0,LL _dis = 0):id(_id),dis(_dis){} }; queue<Node>q; vector<int> ans; int main() { int n,m,x; cin >> n >> m; for(int i = 0;i<n;++i) { cin >> x; q.push(Node(x,0)); s.insert(x); } int cnt = 0; LL sum = 0; while(!q.empty()) { Node t = q.front(); q.pop(); int x = t.id+1,dis = t.dis+1; // cout << x << endl; if(s.find(x)==s.end()) { sum+=dis; ans.push_back(x); ++cnt; s.insert(x); q.push(Node(x,dis)); } if(cnt>=m) break; x = t.id-1; if(s.find(x)==s.end()) { sum+=dis; ans.push_back(x); ++cnt; s.insert(x); q.push(Node(x,dis)); } if(cnt>=m) break; } cout << sum << endl; for(int i = 0;i<m;++i) { cout << ans[i]; if(i==m-1) printf("\n"); else printf(" "); } return 0; }
E. New Year Parties
题意 :
在一个坐标轴上每一个整数点上都有一座房子,然后输入一些人所在的房子位置,每个人可以向左也可以向右移动,只能移动一次,问能占据的最多的房子数以及最少的房子数分别是多少。
思路:
最少 :将有人的房子的后两座房子与当前这座房子分为一类,经过推理可知,无论有什么情况,将这三栋房子里的人都能转移到同一栋里,且这样一定是最优解。
最多:将一串连续的有人的房子一起讨论,加入人数总数sum比长度长的话,则代表这是可扩展的,如果左边可扩展的话,就扩展左边,同时检查右边是否可扩展,如果可扩展,那就扩展并将right置为1,标记一下这个段扩展了右边界。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5+10; int a[maxn],b[maxn]; int main() { int n; cin >>n; int x; for(int i = 1;i<=n;i++) { cin >> x; a[x]++; b[x]++; } int ma = 0,mi = 0; int dist = 2; bool right = 0; for(int i = 1;i<=n;i++) { if(!b[i]) { ++dist; continue; } int j = i-1; int sum = 0; while(j+1<=n&&b[j+1]) { ++j; sum+=b[j]; } ma+=(j-i+1); if(sum>j-i+1&&(!right||dist>1)) { --sum; ++ma; } right = false; if(sum>j-i+1){ right = true; ++ma; } i = j; dist = 0; } for(int i =1;i<=n;++i) { if(!b[i]) { continue; } else mi++; i+=2; } printf("%d %d\n",mi,ma); return 0; }
F. DIY Garland
题意:
共有n个节点,n-1条线,很明显,这是个树,对于每一条线,其必定连接一个父节点和一个子节点,现在给出每条线所连接的父节点,并且给出的顺序是按照切断这条线后与树断开的联通分量的结点权值和(标记为i的结点的权值为2^i,i属于1到n)从大到小。让给出这个树的根节点以及每条边所连接的两个点。
思路:
首先,在输入的第一个节点一定是根节点,然后每个结点在输入中出现的次数实际上就是这个节点的子节点数,而在输入中没出现的结点就是叶节点。可以认为,在输入序列中最后一个数就是叶节点中权值最小的那个节点的父节点,然后输出这条线,并将这个父节点的孩子数减一,如果这个父节点没有其他孩子,则可以把这个父节点也当作叶节点来考虑,每一次取出的叶结点应该是所有未连接的叶节点中权值最小的,所以可以用优先队列来存储待处理的也叶节点。或许有疑问,我们把父节点当作叶节点来处理,这个结点事实上是由子节点,包括他的连通分量的和应该是包括他的子节点的权值。那么会不会这个权值和会超过另一个权值比这个父节点大的的结点,这样的话我们的跟据重要性从小到大去连接叶节点与父节点的想法就是错的了,这种情况是不存在的,因为(1+2+……+2^(n-1)<2^n)。
#include <bits/stdc++.h> using namespace std; priority_queue<int,vector<int>,greater<int> >q; const int maxn = 2e5+10; int depth[maxn]; int num[maxn]; int main() { int n,x; cin >> n; for(int i = 0;i<n-1;i++) { cin >> num[i]; depth[num[i]]++; } printf("%d\n",num[0]); //depth[num[0]]--; for(int i =1;i<=n;i++) { if(!depth[i]) q.push(i); } //cout << q.size() << endl; //int cur = n-1; for(int i = n-2;i>=0;i--) { // cout << num[i] << endl; int t = q.top(); //cout << t << " " << num[i] << endl; q.pop(); printf("%d %d\n",t,num[i]); --depth[num[i]]; if(!depth[num[i]]) q.push(num[i]); } return 0; }