Codeforces Round #371(Div.1)
来源:互联网 发布:chrome json 插件 编辑:程序博客网 时间:2024/05/19 16:50
A. Sonya and Queries
题目链接
分类:思维、map容器应用
1.题意概述
- 定义一个集合A,你有三种操作
+ ai —— 将该元素加入集合当中(允许相同元素重复)− ai —— 将该元素从集合中删除(保证删除合法性)? s —— 统计符合条件的元素个数- 其中
s 是01串,为0表示该位是偶数,为1表示该位为奇数,如果s 的位数比某元素低,那么前缀自动补0
- 其中
2.解题思路
因为不需要具体到每个元素是谁,因此我们只关心每个元素特征。因此我们考虑统计每个加入、删除的元素。对于元素每一位:
- 如果是偶数,则它这位为0
- 如果是奇数,则它这位是1
最后结果既可以用二进制表示,也可以用十进制表示,考虑到数很大,但是操作次数不多,可以用map容器维护这个特征值。
3.AC代码
#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define maxn 100010#define lson root << 1#define rson root << 1 | 1#define lent (t[root].r - t[root].l + 1)#define lenl (t[lson].r - t[lson].l + 1)#define lenr (t[rson].r - t[rson].l + 1)#define N 1111#define eps 1e-6#define pi acos(-1.0)#define e exp(1.0)using namespace std;const int mod = 1e9 + 7;typedef long long ll;typedef unsigned long long ull;map<ll, int> vis;int main(){#ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); long _begin_time = clock();#endif int t; char opt[3]; ll x; vis.clear(); scanf("%d", &t); while (t--) { scanf("%s%I64d", opt, &x); int pos = 0, tmp = 0; //printf("%d : ", x); while (x) { int dig = (x % 10) & 1; if (dig) tmp += pow(2, pos); pos++; x /= 10; } //printf("%d : %d\n", tmp, pos); if (opt[0] == '+') vis[tmp]++; else if (opt[0] == '-') { vis[tmp]--; if (!vis[tmp]) vis.erase(tmp); } else printf("%d\n", vis[tmp]); }#ifndef ONLINE_JUDGE long _end_time = clock(); printf("time = %ld ms.", _end_time - _begin_time);#endif return 0;}
B. Searching Rectangles
题目链接
分类:二分、构造
1.题意概述
- 给你一个
r×c 的矩阵,其中有两个不相交的长方形(可能是点的形式),你可以最多询问200次,某个区域内完整包含的长方形个数。需要你确定这两个长方形的坐标(左上角和右下角),有意思点在于这是人机交互题,必须用flush
进行。
2.解题思路
- 先考虑单独在坐标格纸中只有一个长方形情况,对于每一条边,我们询问策略可以考虑二分地进行:
- 例如右侧边,我们可以固定左上角坐标(1,1),二分地寻找右下角坐标(x,n),判断一个坐标合法只需看人机交互返回结果为0还是为1。
- 下面回到原问题,因为题目保证长方形直接不会交叉,那么我们总能找到边界线把它们分成两个单独的区域,使得问题转化为上面那种简单的模式。容易观察出来,这个分界线不是平行于x轴就是y轴。
3.AC代码
#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define maxn 100010#define lson root << 1#define rson root << 1 | 1#define lent (t[root].r - t[root].l + 1)#define lenl (t[lson].r - t[lson].l + 1)#define lenr (t[rson].r - t[rson].l + 1)#define N 1111#define eps 1e-6#define pi acos(-1.0)#define e exp(1.0)using namespace std;const int mod = 1e9 + 7;typedef long long ll;typedef unsigned long long ull;struct node{ int x1, y1, x2, y2; node() {} node(int a, int b, int c, int d) { x1 = a; y1 = b; x2 = c; y2 = d; }};vector<node> side, res;int query(int x1, int y1, int x2, int y2){ if (x1 > x2 || y1 > y2) return 0; printf("? %d %d %d %d\n", x1, y1, x2, y2); fflush(stdout); int ans; scanf("%d", &ans); return ans;}void get_line(int n){ int l = 0, r = n + 1; // parell y while (l < r) { int mid = l + r >> 1; int ans1 = query(1, 1, mid, n); int ans2 = query(mid + 1, 1, n, n); if (ans1 == 1 && ans2 == 1) { side.push_back(node(1, 1, mid, n)); side.push_back(node(mid + 1, 1, n , n)); return; } else if (ans1 == 0 && ans2 == 0) break; else if (ans1 > 0) r = mid; else if (ans2 > 0) l = mid + 1; } // parellx l = 0, r = n + 1; while (l < r) { int mid = l + r >> 1; int ans1 = query(1, 1, n, mid); int ans2 = query(1, mid + 1, n, n); if (ans1 == 1 && ans2 == 1) { side.push_back(node(1, 1, n, mid)); side.push_back(node(1, mid + 1, n, n)); return; } else if (ans1 == 0 && ans2 == 0) break; else if (ans1 > 0) r = mid; else if (ans2 > 0) l = mid + 1; }}void solve(int x1, int y1, int x2, int y2){ int u, d, l, r; int x, y, mid; x = 0, y = y2 - y1 + 2; while(x < y) { mid = x + (y - x) / 2; int ans = query(x1, y1, x2, y1 + mid - 1); if(ans == 1) y = mid; else x = mid + 1; } u = y1 + x - 1; x = 0, y = y2 - y1 + 2; while(x < y) { mid = x + (y - x) / 2; int ans = query(x1, y1 + mid, x2, y2); if(ans == 0) y = mid; else x = mid + 1; } d = y1 + x - 1; x = 0, y = x2 - x1 + 2; while(x < y) { mid = x + (y - x) / 2; int ans = query(x1 + mid, y1, x2, y2); if(ans == 0) y = mid; else x = mid + 1; } l = x1 + x - 1; x = 0, y = x2 - x1 + 2; while(x < y) { mid = x + (y - x) / 2; int ans = query(x1, y1, x1 + mid - 1, y2); if(ans == 1) y = mid; else x = mid + 1; } r = x1 + x - 1; res.push_back(node(l, d, r, u));}int main(){#ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); long _begin_time = clock();#endif int n; res.clear(); side.clear(); scanf("%d", &n); get_line(n); solve(side[0].x1, side[0].y1, side[0].x2, side[0].y2); solve(side[1].x1, side[1].y1, side[1].x2, side[1].y2); printf("! %d %d %d %d %d %d %d %d\n", res[0].x1, res[0].y1, res[0].x2, res[0].y2, res[1].x1, res[1].y1, res[1].x2, res[1].y2); fflush(stdout);#ifndef ONLINE_JUDGE long _end_time = clock(); printf("time = %ld ms.", _end_time - _begin_time);#endif return 0;}
C. Sonya and Problem Wihtout a Legend
题目链接
分类:dp、思维、排序
1.题意概述
- 给你一个长度为n的序列,可以进行若干次操作,每次操作让它+1或者-1,问你最少需要经过多少次操作能够使得它严格单调递增。
2.解题思路
- 首先考虑不是严格递减的情况:
- 不严格递减最后修改完成后的各个数一定是原序列中的某一个数——这个大概可以这么理解:原序列,从左到右扫过去,如果左边的大于右边的,要嘛左边的减掉使其等于右边的,要嘛右边的加上使其等于左边的。
- 考虑动态规划:
dp[i][j] 表示序列前i个数都单调递增且第i个数更改为不大于原序列中第j个数的最少代价,那么转移方程是: dp[i][j]=min(dp[i][j−1],dp[i−1][j]+abs(a[i]−b[i]))
- 回到原问题,要求严格单调递增,可以转化成不严格单调递增情况:
- 怎么做?让原序列每个数
a[i] 减去i - 因为:
ai<ai+1⇔ai≤ai+1−1⇔ai−i≤ai+1−(i+1) 的01矩阵,在给定正方形区域(x1,y1) ~(x2,y2) 内由1构成的正方形矩阵的最大边长。
2.解题思路
- 容易想到的是
dp[i][j] 表示以(i,j) 为右下角的正方形的边长,那么很容易得到转移方程:dp[i][j]=min(dp[i−1][j],dp[i][j−1],dp[i−1][j−1])
- 那么我们对于每个询问区间
(x1,y1) 、(x2,y2) ,我们考虑二分答案:对于每个mid,我们在区间(x1+mid−1,y1+mid−1) ~(x2,y2) 内是否存在边长为mid的矩形即可。 - 但是考虑到询问次数很大,我们可以考虑
2D sparse table 预处理出以每个点为右下角的区间最值。
3.AC代码
#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define maxn 100010#define lson root << 1#define rson root << 1 | 1#define lent (t[root].r - t[root].l + 1)#define lenl (t[lson].r - t[lson].l + 1)#define lenr (t[rson].r - t[rson].l + 1)#define N 1001#define eps 1e-6#define pi acos(-1.0)#define e exp(1.0)using namespace std;const int mod = 1e9 + 7;typedef long long ll;typedef unsigned long long ull;int dp[N][N][11][11], st[N];void ST(int n, int m){ st[0] = -1; for (int i = 1; i <= max(n, m); i++) st[i] = (i & (i - 1)) == 0 ? st[i - 1] + 1 : st[i - 1]; for (int a = 0; a <= st[n]; a++) for (int b = 0; b <= st[m]; b++) if (a + b) { for (int i = 1; i + (1 << a) - 1 <= n; i++) for (int j = 1; j + (1 << b) - 1 <= m; j++) if (a) dp[i][j][a][b] = max(dp[i][j][a - 1][b], dp[i + (1 << a - 1)][j][a - 1][b]); else dp[i][j][a][b] = max(dp[i][j][a][b - 1], dp[i][j + (1 << b - 1)][a][b - 1]); }}int rmq(int x1, int y1, int x2, int y2){ int k1 = st[x2 - x1 + 1]; int k2 = st[y2 - y1 + 1]; x2 -= (1 << k1) - 1; y2 -= (1 << k2) - 1; return max(max(dp[x1][y1][k1][k2], dp[x1][y2][k1][k2]), max(dp[x2][y1][k1][k2], dp[x2][y2][k1][k2]));}int main(){#ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); long _begin_time = clock();#endif int n, m, q; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { int x; scanf("%d", &x); if (x) dp[i][j][0][0] = min(dp[i - 1][j][0][0], min(dp[i][j - 1][0][0], dp[i - 1][j - 1][0][0])) + 1; } ST(n, m); scanf("%d", &q); while (q--) { int x1, x2, y1, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); int ans = 0, l = 0, r = min(x2 - x1, y2 - y1) + 1; while (l <= r) { int mid = l + r >> 1; if (rmq(x1 + mid - 1, y1 + mid - 1, x2, y2) >= mid) { ans = mid; l = mid + 1; } else r = mid - 1; } printf("%d\n", ans); }#ifndef ONLINE_JUDGE long _end_time = clock(); printf("time = %ld ms.", _end_time - _begin_time);#endif return 0;}
E. Sonya Partymaker
题目链接
分类:二分、dp
1.题意概述
- 有n个人,m个凳子,其中凳子被编号为1…m围成环形。1和m、2相邻,2和1、3相邻,以此类推…现在每个人可以选择顺时针/逆时针地走动,边走边把当前位置凳子给抽走,问你最短时间将凳子都抽完。
2.解题思路
- 考虑1到n所有间隙的最大值,假设n和1的间隙是最大的,设为M。显然最终答案
ans≤M 。 - 我们考虑二分答案
ans ,因为答案肯定小于最大值,也就是这个最优策略一定满足:1,n 直接有人面向对方相对着走(左右覆盖)。- 假设其他人都是顺时针边走边提凳子,那么我们容易发现最优解中ID为1和2之间一定有人向左走!否则,例如3才向左走,那么1对答案没有贡献(因为n和1间距最大,1如果向右走,n还是得走到头游戏才结束。以此类推,以三个人为周期去递推:
- 我们枚举
、1、2 谁向左走,用dp[i] 表示前i 个人一共覆盖(搬走)多少个凳子,对于每个i ,转移方程是:i 向右走,那么要求dp[i−1]≥ai−1 ,这时候可以用ai+ans 新答案。i 向左走,那么要求dp[i−1]≥ai−ans−1 ,这时候可以用ai 更新答案。i 向左走,但是玩家(i−1) 依然向左走,那么要求dp[i−2]≥ai−ans−1 ,同时用ai−1+ans 更新答案。
3.AC代码
#include <bits/stdc++.h>#define INF 0x3f3f3f3f#define maxn 100010#define lson root << 1#define rson root << 1 | 1#define lent (t[root].r - t[root].l + 1)#define lenl (t[lson].r - t[lson].l + 1)#define lenr (t[rson].r - t[rson].l + 1)#define N 1111#define eps 1e-6#define pi acos(-1.0)#define e exp(1.0)using namespace std;const int mod = 1e9 + 7;typedef long long ll;typedef unsigned long long ull;int n, m, a[maxn], dp[maxn];bool check(int x){ for (int sta = 0; sta < 2 && sta < n; sta++) { dp[sta] = sta ? max(a[0] + x, a[1]) : a[0]; for (int i = sta + 1; i < n; i++) { dp[i] = dp[i - 1]; if (dp[i - 1] >= a[i] - x - 1) // left dp[i] = max(dp[i], a[i]); if (dp[i - 1] >= a[i] - 1) // right dp[i] = max(dp[i], a[i] + x); if (i >= 2 && dp[i - 2] >= a[i] - x - 1) dp[i] = max(dp[i], a[i - 1] + x); } if (dp[n - 1] >= min(m - 1, m + a[sta] - x - 1)) return 1; } return 0;}int main(){#ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); long _begin_time = clock();#endif scanf("%d%d", &m, &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); sort(a, a + n); pair<int, int> best(a[0] + m - a[n - 1], 0); for (int i = 1; i < n; i++) best = max(best, make_pair(a[i] - a[i - 1], i)); rotate(a, a + best.second, a + n); for (int i = n - 1; i >= 0; i--) { a[i] -= a[0]; if (a[i] < 0) a[i] += m; } int l = 0, r = a[0] + m - a[n - 1] - 1; int ans = r; while (l <= r) { int mid = l + r >> 1; if (check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } printf("%d\n", ans);#ifndef ONLINE_JUDGE long _end_time = clock(); printf("time = %ld ms.", _end_time - _begin_time);#endif return 0;}
- 怎么做?让原序列每个数
阅读全文
1 0
- Codeforces Round #371(Div.1)
- Codeforces Round #174 (Div. 1)(完全)
- Codeforces Round #177 (Div. 1)(完全)
- Codeforces Round #179 (Div. 1)(完全)
- Codeforces Round #219 (Div. 1)(完全)
- Codeforces Round #221 (Div. 1)(完全)
- Codeforces Round #124 (Div. 2) (Div.1)
- Codeforces Round #371 (Div. 2)
- Codeforces Round #371 (Div. 2)
- Codeforces Round #371 (Div. 2)
- Codeforces Round #110 (Div. 1)
- Codeforces Round #138 (Div. 1)
- Codeforces Round #140 (Div. 1)
- Codeforces Round #153 (Div. 1)
- Codeforces Round #157 (Div. 1)
- Codeforces Round #160 (Div. 1)
- Codeforces Round #162 (Div. 1)
- Codeforces Round #165 (Div. 1)
- 全面剖析Redis Cluster原理和应用
- freecodecamp项目---twitch API
- Win10中护眼色
- div内部的div margin-top 上层div动了 本身自身没动
- 剑指offer-删除链表重复节点
- Codeforces Round #371(Div.1)
- 利用Javascript制作网页特效(时间特效)
- 完美下载Android源码Ubuntu版
- Listener监听器
- 开博了。。
- Redis单线程架构
- JAVA 8函数式编程(二):每个函数都是可以传递的对象
- Linux内建命令及Bash Shell
- Java 求闰年 (细细品味if语句分开写和合到一起写得到的不一样的结果)