Codeforces Round #540 (Div. 3) A,B,C,D2,E,F1
A. Water Buying
链接:http://codeforces.com/contest/1118/problem/A
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long int main() { ll n,a,b,m; cin>>n; for(int i = 1;i <= n;i ++){ cin>>m>>a>>b; if(a*2 <= b) cout<<m*a<<endl; else{ if(m%2==0) cout<<m/2*b<<endl; else cout<<m/2*b+a<<endl; } } return 0; }
B. Tanya and Candies
链接:http://codeforces.com/contest/1118/problem/B
题意:给你一串序列,去掉其中一个数字,剩下的序列满足奇数数字之和等于偶数数字之和,问有多少个这样的数字
思路:从后往前用前缀和处理下,得到当前点到序列尾的奇数和与偶数和,去掉当前点造成的影响其实就是后面的奇数和与偶数和互换,再分别加上当前点前面点的奇数和与偶数和,判断下是否相等就好了。
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int M = 2e5+10; int x[M],a[M],b[M],n; int main() { cin>>n; for(int i = 1;i <= n;i ++){ cin>>x[i]; } for(int i = n;i >= 1;i --){ a[i] = a[i+1]; b[i] = b[i+1]; if(i%2==0) a[i] += x[i]; else b[i] += x[i]; } int ans = 0; for(int i = 1;i <= n;i ++){ int ans1 = a[1] - a[i]; int ans2 = b[1] - b[i]; //cout<<ans1<<" "<<ans2<<endl; ans1 += b[i+1]; ans2 += a[i+1]; // cout<<ans1<<" "<<ans2<<endl; if(ans1 == ans2) ans++; } cout<<ans<<endl; return 0; }
C. Palindromic Matrix
链接:http://codeforces.com/contest/1118/problem/C
题意:给出一段序列,让你用序列中的数构造一个矩阵,这个矩阵的行列颠倒也不会发生变化,这种矩阵被称为回文矩阵
思路:当n为偶数时,序列中每个数出现次数必须为4的倍数,如果不是那就无法构造,奇数是,序列中的数出现次数%4==2的不能超过n个||奇数次数的不能超过一个||数先构造中间的十字架构造周围四个矩阵时如果出现某个数出现次数不为4的次数时也无法构造。主要就是奇数构造起来有点麻烦,我们先用%4==2与奇数次数的那些数构造中间的十字架,构造完就根据左上角的矩阵依次填数,每填一个就把左下,右上,右下三个区域对应的点也填上这个数,保证对应。
实现代码:
#include<bits/stdc++.h> using namespace std; const int M = 1e3+10; queue<int>v; queue<int>v2; int mp[M],n,x; int g[30][30]; int v1[M]; int main() { int flag = 1,tot = 0; cin>>n; for(int i = 1;i <= n*n;i ++){ cin>>x; mp[x] ++; if(mp[x] == 1) v.push(x),v1[++tot]=x; } if(n%2==0){ for(int i = 1;i <= n/2;i ++){ for(int j = 1;j <= n/2;j ++){ int now = v.front(); if(mp[now]<4){ flag = 0;break; } else if(mp[now] == 4){ v.pop();mp[now] = 0; } else mp[now] -= 4; g[i][j] = now; g[n-i+1][j] = now; g[n-i+1][n-j+1] = now; g[i][n-j+1]=now; } } } else{ int cnt = 0,cnt1 = 0; for(int j = 1;j <= tot;j ++){ int i = v1[j]; if(mp[i]%2 == 1){ cnt++,g[n/2+1][n/2+1] = i; if(mp[i]!=1) mp[i]-=1; } if(mp[i]%4 == 2){ cnt1++;v2.push(i); } } if(cnt > 1||cnt1 > n-1) flag = 0; for(int i = 1;i <= tot;i ++){ if(mp[v1[i]]%4==0) v2.push(v1[i]); } for(int i = 1;i <= n/2;i ++){ int now = v2.front(); if(mp[now] == 2){ v2.pop(); mp[now] = 0; } else if(mp[now]%4==2&&mp[now]>2){ mp[now] -= 2;v2.pop(); v2.push(now); } else{ mp[now] -= 2; } g[i][n/2+1] = now; g[n-i+1][n/2+1] = now; } for(int i = 1;i <= n/2;i ++){ int now = v2.front(); if(mp[now] == 2){ v2.pop(); mp[now] = 0; } else if(mp[now]%4==2&&mp[now]>2){ mp[now] -= 2,v2.pop(),v2.push(now); } else { mp[now]-=2; } g[n/2+1][i] = now; g[n/2+1][n-i+1] = now; } for(int i = 1;i <= n/2;i ++){ for(int j = 1;j <= n/2;j ++){ int now = v2.front(); if(mp[now] == 2) { flag = 0;break; } else if(mp[now] == 4){ mp[now] = 0; v2.pop(); } else { mp[now] -= 4; } g[i][j] = now;g[n-i+1][j] = now; g[n-i+1][n-j+1]=now; g[i][n-j+1]=now; } } } if(flag){ cout<<"YES"<<endl; for(int i = 1;i <= n;i ++){ for(int j D2. Coffee and Coursework (Hard Version)= 1;j <= n;j ++){ cout<<g[i][j]<<" "; } cout<<endl; } } else { cout<<"NO"<<endl; } }
D1. Coffee and Coursework (Hard Version)
同下
D2. Coffee and Coursework (Hard Version)
链接:http://codeforces.com/contest/1118/problem/D2
题意:喝咖啡,喝一杯咖啡可以工作ai个作业,一共有n杯咖啡,m个作业,一天内喝多杯咖啡,咖啡作用会减弱,完成这些作业最快需要多少天。
思路:直接二分需要的天数,判断下当前天数能否完成,判断时,最优的喝法肯定是每天喝的杯数尽量一样(这样咖啡作用被减弱的最少),每天先喝作用大的咖啡,作用小的留到后面,这样可以i得到当前天数能完成最多的作业,与需要完成的作业对比下,大于等于的话就往左区间找,小于的话就往右区间找。
实现代码;
#include<bits/stdc++.h> using namespace std; #define ll long long const ll M = 2e5 + 10; ll v[M],a[M]; bool cmp(ll x,ll y){ return x > y; } int main() { ll n,m,cnt = 0,ans = 0; cin>>n>>m; for(ll i = 1;i <= n;i ++){ cin>>a[i]; ans += a[i]; } if(ans < m){ cout<<-1<<endl; return 0; } ll en = n; sort(a+1,a+n+1,cmp); ll l = 1,r = n; while(l < r){ ll mid = (l + r) >> 1; ll num = n/mid; for(ll i = 0;i <= num-1;i ++){ for(ll j = 1;j <= mid;j ++){ v[++cnt] = i; } } for(ll i = 1;i <= (n%mid);i ++) v[++cnt] = num; sort(v+1,v+1+cnt); ll kk = 0; for(ll i = 1;i <= cnt;i ++){ kk += max(0*1LL,a[i]-v[i]); } for(ll i = 1;i<= cnt;i ++) v[i] = 0; cnt = 0; if(kk >= m) r = mid,en = mid; else l = mid+1; } cout<<en<<endl; }
E. Yet Another Ball Problem
链接:http://codeforces.com/contest/1118/problem/E
思路:沙雕构造题,和a题一个难度,看完四个条件和样例基本就能秒出了。
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long int main(){ ll n,m,cnt = 0; cin>>n>>m; if(n > m*(m-1)) cout<<"NO"<<endl; else { cout<<"YES"<<endl; for(ll i = 1;i <= m;i ++){ for(ll j = i+1;j <= m;j ++){ cout<<i<<" "<<j<<endl; cnt++; if(cnt == n) return 0; cout<<j<<" "<<i<<endl; cnt++; if(cnt == n) return 0; } } } return 0; }
F1. Tree Cutting (Easy Version)
链接:http://codeforces.com/contest/1118/problem/F1
题意:给你一棵树,树上的点分别为无色,红色,蓝色,现在删掉一条边,树变成两棵树,这两棵树不能同时有红蓝两种颜色,问有几条这样的边
思路:从树的叶子节点往上更新信息(子树中红色点的数量和蓝色点的数量),如果某个点的子树红色点数量等于整棵树的红色点数量且没有蓝色点,那么这个点与父节点的边是可以被删除的(蓝色同理),我们直接用dfs跑一遍就好了。
实现代码:
#include<bits/stdc++.h> using namespace std; const int M = 3e5+10; vector<int>g[M]; struct node{ int x,y; }q[M]; int n,m,a1,b1,a[M],cnt; void dfs(int u,int fa){ if(a[u]==1) q[u].x++; else if(a[u]==2) q[u].y++; for(int i = 0;i < g[u].size();i ++){ int v = g[u][i]; if(v == fa) continue; dfs(v,u); q[u].x += q[v].x; q[u].y += q[v].y; } if((q[u].x == a1&&q[u].y==0)||(q[u].y==b1&&q[u].x==0)) cnt++; return ; } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n; for(int i = 1;i <= n;i ++){ cin>>a[i]; if(a[i] == 1) a1++; else if(a[i] == 2) b1 ++; } int x,y; for(int i = 2;i <= n;i ++){ cin>>x>>y; g[x].push_back(y); g[y].push_back(x); } dfs(1,0); cout<<cnt<<endl; }