Codeforces Round #222 (Div. 2) 题解
A.Playing with Dice
题意:输入ab,问1~6中有几个数离a近,几个数距离ab相等,几个数离b近
思路:直接暴力答案
代码:
#include <bits/stdc++.h>using namespace std; int main() { int a,b; scanf("%d%d", &a, &b); int as = 0, qw = 0, zx = 0; for(int i = 1; i <= 6; i++) { int aa = abs(a - i); int bb = abs(b - i); if(aa < bb) as++; if(aa == bb) qw++; if(aa > bb) zx++; } printf("%d %d %d\n",as,qw,zx); return 0; }
C.Maze
题意:给一个n*m的地图,地图中’.’表示空地,’#’表示墙,现在空地为一个联通块,现在需要在k个地方建墙,是的剩余的部分还是一个联通块
思路:假设空地的格数为s个,那么多搜s-k格,广搜到的部分就是最后剩下的联通块,其他的都为墙
代码:
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> pii; int n, m, k; char mp[505][505]; int vis[505][505]; int top; int dx[10] = {1,-1,0,0}; int dy[10] = {0,0,1,-1}; int sum ; void bfs(int x,int y) { queue<pii> q; while(!q.empty())q.pop(); pii as = make_pair(x,y); vis[x][y] = 1; q.push(as); int cnt = 0; sum -= k; while(!q.empty() && cnt < sum){ pii now = q.front(); mp[now.first][now.second] = '!'; cnt ++; q.pop(); for(int i = 0; i < 4; i++){ int xx = now.first + dx[i]; int yy = now.second + dy[i]; if(xx < 1 || xx > n || yy < 1 || yy > m || mp[xx][yy] == '#' || vis[xx][yy])continue; vis[xx][yy] = 1; pii as = make_pair(xx, yy); q.push(as); } } } int main() { scanf("%d%d%d", &n, &m, &k); sum = 0; for(int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> mp[i][j]; if(mp[i][j] == '.')sum ++; } } bool ok = true; for(int i = 1; i <= n && ok; i++) { for(int j = 1; j <= m && ok; j++) { if(vis[i][j] || mp[i][j] == '#')continue; bfs(i, j); ok = false; } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { if(mp[i][j] == '!')mp[i][j] = '.'; else if(mp[i][j] == '.') mp[i][j] = 'X'; printf("%c",mp[i][j]); } puts(""); } return 0; }
D.Preparing for the Contest
题意:有n个bug,每个bug有一定的困难值,有m个人,每个人都有能力值bi以及费用ci,每个人只需要花一次费用就可以一直修bug,但是他只能修小于等于他能力值的bug,一个bug修一天,现在有s圆,问最少几天,并且费用在s以内,可以把bug修完,打印方案
思路:因为天数是单调的,所以二分枚举,我们对问题的难度进行排序,前mid天给一个人修,就这样一直找费用最小的人,费用最小的人用优先队列维护,每次弹出最便宜的
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+7; int n, m, s; int ans[maxn]; struct node { int b, val, id; bool operator <(node a) const { return val>a.val; } }a[maxn], c[maxn]; bool cmp(node A, node B) { return A.b > B.b; } bool check(int t) { int res = 0; priority_queue<node> q; while(!q.empty())q.pop(); for(int i = 1, j = 1; j <= m; j += t) { while(i <= n && a[j].b <= c[i].b) { q.push(c[i]); i++; } if(q.empty()) return false; node as = q.top(); q.pop(); res += as.val; for(int k = j; k < min(j+t, m+1); k++) { ans[a[k].id] = as.id; } if(res > s) return false; } return true; } int main() { scanf("%d%d%d", &n, &m, &s); for(int i = 1; i <= m; i++) { scanf("%d", &a[i].b); a[i].id = i; a[i].val = 0; } for(int i = 1; i <= n; i++) { scanf("%d", &c[i].b); } for(int i = 1; i <= n; i++) { scanf("%d", &c[i].val); c[i].id = i; } sort(a + 1, a + 1 + m, cmp); sort(c + 1, c + 1 + n, cmp); int ok = 0; for(int i = 1; i <= n; i++) { if(c[i].b >= a[1].b && c[i].val <= s){ ok = 1; break; } } if(!ok) { puts("NO"); return 0; } int L = 1, R = m, res = 0; while(L <= R) { int mid = (L + R) >> 1; if(check(mid)) { R = mid - 1; res = mid; } else L = mid + 1; } check(res); puts("YES"); for(int i = 1; i <= m; i++) { if(i > 1)printf(" "); printf("%d",ans[i]); } puts(""); return 0; }
E. Captains Mode
题意:有n个英雄,每个英雄有他的力量值,有两队进行bp,一共m(20)次bp操作,问在m次bp后1队的英雄力量总和减去二队的力量总和最大值为多少
思路:因为m很小,所以状压,dp[i]表示状态为i时,1队减2队的最大值,因为一个想让差值增大,一个想减小,所以1队时的转移为dp[i] = max(dp[i | (1<<j)] + s[j + 1])为2队时中间的符号相减,倒着枚举状态,使后面的状态在前面都算过了
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6+7; int s[maxn]; int dp[1<<21]; int op[25],a[25]; bool cmp(int x,int y) { return x > y; } int gett(int x) { int res = 0; for(; x; res++)x &= x - 1; return res; } int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &s[i]); } sort(s + 1, s + 1 + n, cmp); int m; scanf("%d", &m); for(int i = 0; i < m; i++) { char ch; scanf("\n%c%d", &ch, &a[i]); op[i] = (ch == 'p'); } dp[(1 << m) - 1] = 0; for(int i = (1<<m) - 2; i >= 0; i--) { int num = gett(i); if(a[num] == 1) { dp[i] = -0x3f3f3f3f; for(int j = 0; j < m; j++) { if((i & (1<<j)) == 0) dp[i] = max(dp[i], dp[i | (1<<j)] + op[num] * s[j + 1]); } } else { dp[i] = 0x3f3f3f3f; for(int j = 0; j < m; j++) { if((i & (1<<j)) == 0) dp[i] = min(dp[i], dp[i | (1<<j)] - op[num] * s[j + 1]); } } } printf("%d\n",dp[0]); return 0; }