contest链接:https://codeforces.com/contest/1283
A. Minutes Before the New Year
题意:给一个当前时间,输出离第二天差多少分钟
思路:略
AC代码:
1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 const int mod = 1e9+7; 8 const int maxn = 1e5+5; 9 typedef long long ll; 10 int main(){ 11 int t; 12 cin>>t; 13 while(t--){ 14 int h,m;cin>>h>>m; 15 h = 23 - h,m = 60 - m; 16 cout<<(h)*60+m<<endl; 17 } 18 return 0; 19 }
B. Candies Division
题意: 给每个人分糖果,得到糖果数最多的人的糖果数与得到糖果数最少的人的数量之差不能大于一。并且得到糖果数量最多的人不得多于人数的一半。
思路:略
AC代码:
1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 const int mod = 1e9+7; 8 const int maxn = 1e5+5; 9 typedef long long ll; 10 int main(){ 11 int t; 12 cin>>t; 13 while(t--){ 14 ll n,k;cin>>n>>k; 15 ll t = n/k; 16 ll d = n - t*k; 17 ll t1 = min(k/2,d); 18 cout<<t*k+t1<<endl; 19 } 20 return 0; 21 }
C. Friends and Gifts
题意:每个人都要给其他一个人一个礼物,并且每个人都要收到一个礼物。请你设计一种合法的赠送礼物的方法,使得每个人都赠送非自己的人一个礼物,并且从其他人那里收到一个礼物。
题解:最终合法的方法是若干个有向环,输入的时候存每个人的出度和入度,出度表示赠送礼物,入度表示接收礼物,最终保证每个人的出入度都是1。再输入统计完之后首先排除掉构成环的所有人,因为他们已经满足题意要求。再者是既没有得到礼物,又没有赠送礼物的人,即出入度都是0,然后让他们互相连接起来,记作集合R,最终让入度为1出度为0的人连接集合R,集合R中进行操作过后,留下一个人出度为0,再让这个人连接最后一个出度为1,入度为0的人,总体构成一个环即可。
AC代码:
1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 const int mod = 1e9+7; 8 const int maxn = 2e5+5; 9 typedef long long ll; 10 struct node{ 11 int in; 12 int out; 13 }g[maxn]; 14 15 int main(){ 16 int n; 17 cin>>n; 18 for(int i = 1;i<=n;i++){ 19 g[i].in = 0; 20 } 21 for(int i = 1;i<=n;i++) { 22 int t;cin>>t; 23 g[i].out = t; 24 g[t].in = i; 25 } 26 int start = -1,end = -1; 27 vector<int> v ,vIn,vOut; 28 for(int i = 1;i<=n;i++){ 29 if(g[i].in != 0 && g[i].out == 0) vOut.push_back(i); 30 if(g[i].in == 0 && g[i].out != 0) vIn.push_back(i); 31 if(g[i].in == 0 && g[i].out == 0) v.push_back(i); 32 } 33 if(v.size() > 1 ){ 34 start = v[0],end = v[v.size() -1]; 35 int first = v[0]; 36 for(int i = 1;i<v.size() -1;i++){ 37 g[start].out = v[i]; 38 start = v[i]; 39 } 40 g[start].out = end; 41 g[end].out = first; 42 } 43 if(v.size() == 1){ 44 int t = vOut[vOut.size() -1]; 45 g[t].out = v[0]; 46 g[v[0]].in = t; 47 vOut.pop_back() ; 48 vOut.push_back(v[0]); 49 } 50 for(int i = 0;i<vOut.size() ;i++){ 51 int cur = vOut[i],next = vIn[i]; 52 g[cur].out = next; 53 54 } 55 for(int i = 1;i<=n;i++){ 56 cout<<g[i].out <<" "; 57 } 58 return 0; 59 }
D. Christmas Trees
题意:给定n个不同的整数点,让你找m个不同的整数点,使得这m个点到到这n个点最小距离之和最小。
思路:贪心一下,首先每个点的x+1和x-1两个坐标到这个点的距离是最短的,之后是x+2,x-2,再之后是x+3,x-3,那么可以想到bfs,首先把n个点存入队列中,找与他们距离为1的点,之后再bfs距离为2的点,如此这个过程直到找到m个点
AC代码:
1 #include<iostream> 2 #include<vector> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 const int mod = 1e9+7; 10 const int maxn = 2e5+5; 11 typedef long long ll; 12 queue<pair<int,int> > q; 13 map<int,bool> vis;//用map记录是否访问过 14 vector<int> v; 15 int main(){ 16 int n,m;cin>>n>>m; 17 while(n--){ 18 int t;cin>>t; 19 vis[t] = 1; 20 q.push({1,t+1}),q.push({1,t-1}); //首先存距离为1的点 21 } 22 ll ans = 0; 23 while( m>0 && !q.empty() ){ 24 pair<int,int> cur = q.front() ; 25 q.pop() ; 26 if(vis[cur.second]!=1){//如果没有遍历过 27 m--; 28 v.push_back(cur.second ); 29 ans+=cur.first; 30 vis[cur.second] = 1; 31 if(vis[cur.second+1] != 1) q.push({cur.first+1,cur.second+1});//距离+1,入队列 32 if(vis[cur.second-1] != 1)q.push({cur.first+1,cur.second-1}); //同上 33 } 34 } 35 cout<<ans<<endl; 36 for(int i = 0;i<v.size() ;i++){ 37 cout<<v[i]<<" "; 38 } 39 return 0; 40 }
E. New Year Parties
题意: 有n个人住在一些房子里,有的人住在同一个房子里。每个人可以选择搬去他的房子左边那个房子或者右边那个房子,亦或是不搬,搬只能向左或向右移动一次。问这些人最少住几个房子和最多住几个房子。
题解:贪心。最小值就是三人聚合起来,聚合在一个房子。最大值就是贪心地尽可能地向空房子移动
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 using namespace std; 7 const int maxn = 2e5+5 ; 8 int x[maxn]; 9 int s[maxn]; 10 int main(){ 11 int n;cin>>n; 12 for(int i = 0;i<n;i++){ 13 int t;cin>>t; 14 x[t] ++; 15 s[t] ++; 16 } 17 int mx = 0,mi = 0; 18 for(int i = 1;i<=n+1;i++){//求最大值 19 if(x[i] == 0 ) continue;//当前为0,没人住就跳过 20 if(x[i-1] == 0 ){//前一个房子为空,就移动过一个人,占一个房子 21 x[i]--; 22 x[i-1]++; 23 } 24 if(x[i]>1){//往前一个房子移动过一个人后,如果还有多余的人能再移动,就尽可能再往后面的房子移动 25 x[i+1]++; 26 x[i]--; 27 } 28 } 29 for(int i = 0;i<=n+1;i++){ 30 if(x[i]!=0) mx++; 31 } 32 vector<int> v; 33 int f = 0,cur = 0; 34 for(int i = 1;i<=n;i++){ 35 if(s[i] != 0){//如果当前房子有人,那么房子+1和-1地方的人都聚合过来,每三个人跳转一次 36 mi++; 37 i+=2;//直接跳转 38 } 39 } 40 cout<<mi<<" "<<mx; 41 return 0; 42 }
F. DIY Garland
题意:一根电线连接着两个点,这两个点分别代表着两个灯,灯有自己的编号i,其亮度是2 ^ i,每根电线的两个灯分别为主灯和副灯,电源从主灯来,电流向副灯。最开始有一个源点灯,所有的电源从此处流入,对于每根电线,定义其重要性为 :切断这根电线后不能通电的所有灯的亮度之和。首先题目按电线的重要性给出n-1条电线的主灯编号,让你从大到小输出每条电线所连接的两个灯的序号(无前后差别)
题解:首先,题目的所描述的结构是一棵树,因为题目是按电线重要性给出的节点主灯,那么第一个节点必定是源点,因为重要性最大。其次因为树的叶子节点度必为1,而且叶子节点必定不是主灯,那么我们可以在输入之后统计叶子节点,同时统计一下输入节点的度。叶子节点的编号用优先队列存储,因为亮度最小最先和重要性低的电线匹配。因为输入的时候电线是按重要性从大到小输入的,那么我们就可以把优先队列中的节点一个一个地与其父亲节点(主灯)匹配,匹配过后,让当前这个主灯的度-1,如果这个此时度变为1,那么加入到优先队列之中,因为他现在成了“叶子节点”,如此过程直到把n-1条边都找到,break即可
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 using namespace std; 8 const int maxn = 2e5+5; 9 int ind[maxn]; 10 vector<pair<int,int> > ans; 11 int main(){ 12 int n; 13 cin>>n; 14 priority_queue<int, vector<int>,greater<int> > q; 15 vector<int> mainLamp; 16 int gird = -1; 17 for(int i = 0;i<n-1;i++){ 18 int lamp; 19 cin>>lamp; 20 if(gird == -1) gird = lamp;//记录源点 21 ind[lamp]++;//记录度 22 mainLamp.push_back(lamp); 23 } 24 for(int i = 1;i<=n;i++){ 25 if(ind[i] == 0){//寻找未出现的叶子节点 26 q.push(i); 27 } 28 } 29 while(!q.empty() ){ 30 int cur = q.top(); 31 q.pop(); 32 int curMainLamp = mainLamp[mainLamp.size()-1]; 33 mainLamp.pop_back();//匹配一个主灯,就弹出一个 34 ans.push_back({curMainLamp,cur});//加入一条边 35 if(ans.size() == n -1 ) break; 36 ind[curMainLamp]--; 37 if(ind[curMainLamp] == 0){ 38 q.push(curMainLamp);//如果度为0,那么变成了叶子节点,加入队列中 39 } 40 } 41 cout<<gird<<endl; 42 for(int i = ans.size() -1;i>=0 ;i--){ 43 cout<<ans[i].first<<" "<<ans[i].second<<endl; 44 } 45 return 0; 46 }