Codeforces Round #693 (Div. 3)A~G解题报告

A Cards for Friends

原题信息

http://codeforces.com/contest/1472/problem/A

解题思路

本题就是一个找 x/2i=old,y/2j=oldx/2^i=old,y/2^j=oldx/2i=old,y/2j=old, 返回 2i∗2j>=n2^i*2^j>=n2i∗2j>=n
一般这样的题目都需要注意使用 LL

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <fstream>
using namespace std;typedef long long LL;bool inline Check(LL x, LL y, LL n)
{LL ret = 1;while ((x & 1) == 0){ret <<= 1;x >>= 1;if (ret >= n)return true;}while ((y & 1) == 0){y >>= 1;ret <<= 1;if (ret >= n)return true;}if (ret >= n)   return true;else    return false;
}int main()
{int T;  cin >> T;while (T -- ){static LL x, y, n;cin >> x >> y >> n;if (Check(x, y, n))cout << "YES\n";elsecout << "NO\n";}return 0;
}



B Fair Division

原题信息

http://codeforces.com/contest/1472/problem/B

解题思路

能否将糖果平均分,直接分类讨论
首先统计 1gram1gram1gram 数量为cnt1cnt1cnt1,2gram2gram2gram数量为cnt2cnt2cnt2下面对cnt1,cnt2cnt1,cnt2cnt1,cnt2进行分类讨论
cnt1偶数,cnt2偶数cnt1偶数,cnt2偶数cnt1偶数,cnt2偶数
————可以直接进行平均分
cnt1偶数,cnt2奇数cnt1偶数,cnt2奇数cnt1偶数,cnt2奇数
————当cnt1=0cnt1=0cnt1=0时,不可以平均分
————当cnt1!=0cnt1!=0cnt1!=0时,可以平均分,只需要将cnt1−=2,cnt2++cnt1-=2,cnt2++cnt1−=2,cnt2++即可
cnt1奇数,cnt2偶数或偶数cnt1奇数,cnt2偶数或偶数cnt1奇数,cnt2偶数或偶数
————因为cnt1cnt1cnt1为奇数,导致总的grams根本就是个奇数,是不可能平均分的。

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <fstream>
using namespace std;typedef long long LL;const int N = 200010;
int a[N], n;bool inline Check()
{static int cnt1, cnt2, sum;cnt1 = cnt2 = sum = 0;for (int i = 1; i <= n; i ++ ){sum += a[i];cnt1 += (a[i] == 1);cnt2 += (a[i] == 2);}if (sum & 1)   return false;else if (cnt1 == 0 && cnt2 % 2 == 1)    return false;else    return true;
}int main()
{int T;  cin >> T;while (T -- ){cin >> n;for (int i = 1; i <= n; i ++ ){scanf("%d", &a[i]);}if (Check())cout << "YES\n";elsecout << "NO\n";}return 0;
}



C Long Jumps

原题信息

http://codeforces.com/contest/1472/problem/C

解题思路

一个较为简单的dp,需要注意的是数组下标的特判,防止越界,最好开LL
fif_ifi​表示选择iii做为StartPositionStartPositionStartPosition的游戏结果
那么,我们可以得到递归关系式为
————fi=ai+fi+aif_i=a_i+f_{i+a_i}fi​=ai​+fi+ai​​ 条件为当 i+ai<=ni+a_i<=ni+ai​<=n
————否则fi=aif_i=a_ifi​=ai​
上述的这个讨论就是为了避免数组的越界

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <fstream>
using namespace std;typedef long long LL;const int N = 200010;
int a[N], n;
LL res = 0;
LL f[N];int main()
{int T;  cin >> T;while (T -- ){cin >> n;for (int i = 1; i <= n; i ++ ){scanf("%d", &a[i]);}memset(f, 0, sizeof f);res = 0LL;for (int i = n; i >= 1; i -- ){f[i] = a[i] + (i + a[i] <= n ? f[i + a[i]] : 0);res = max(res, f[i]);}/// printf("###########\n");cout << res << endl;}return 0;
}



D Even-Odd Game

原题信息

http://codeforces.com/contest/1472/problem/D

解题思路

题目大意是给定一个数组,AliceBobAlice BobAliceBob轮流在里面选一个数, AliceAliceAlice选择偶数,那么加和偶数一样大的分, 选择奇数不加分;BobBobBob选择奇数,那么加和奇数一样大的分,选择偶数不加分。
从题意出发,我们不难想到下面这种求解方法,将奇数、偶数分开,两个数组分别进行非递增排序,每次选择的时候从两个数组选取最大的,进行拿出。(好像不分开也行)
对于AliceAliceAlice来讲,选取当前最大的数是偶数,那么加分最多,选取最大的数是奇数,是为了防止BobBobBob加分过多!同理,对于BobBobBob也是如此,下面我们来证明他的合法性。

  • 直接严格证明是很难的,我们不妨辅助的思想来看这个问题,对于人物A来说,他可以选择自己可以加分的数字,也可以选择不让别人加分的数(自己不加分),不让别人加分,就类似于让自己加分(因为让别人加分少了)
  • 也就是说让自己的得分减去另一个人得分更大,自己的赢面更大。因此对于博弈双方,我们只需要选择当前最大数即可。
  • 记得开LL

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <fstream>
using namespace std;typedef long long LL;const int N = 200010;
int a[N], n;
int even_a[N], old_a[N], idx_e, idx_o;
LL score_a, score_b;
int cur_o = 1, cur_e = 1;
bool cmp(int a, int b){ return a > b; }bool Check()
{if (cur_o > idx_o)  return false;if (cur_e > idx_e)  return true;if (old_a[cur_o] >= even_a[cur_e])  return true;else    return false;
}
int main()
{int T;  cin >> T;while (T -- ){cin >> n;score_a = score_b = 0LL;idx_e = idx_o = 0;for (int i = 1; i <= n; i ++ ){scanf("%d", &a[i]);if (a[i] & 1)   old_a[++ idx_o] = a[i];else    even_a[++ idx_e] = a[i];}sort(even_a + 1, even_a + idx_e + 1, cmp);sort(old_a + 1, old_a + idx_o + 1, cmp);cur_o = 1, cur_e = 1;for (int i = 1; i <= n; i ++ ){if (Check())    // 奇数{if (i & 1){cur_o ++;}else{score_b += old_a[cur_o ++];}}else    // 偶数{if (i & 1){score_a += even_a[cur_e ++];}else{cur_e ++;}}}if (score_a == score_b) puts("Tie");else if (score_a > score_b) puts("Alice");else    puts("Bob");}return 0;
}



E Correct Placement

原题信息

解题思路

对于每一个(h,w)(h, w)(h,w)我们需要找到(hi,wi),hi<h,wi<w(h_i, w_i), h_i<h,w_i<w(hi​,wi​),hi​<h,wi​<w的下标,至于另一种情况我们直接 swap(h,w)swap(h, w)swap(h,w)即可,
主要是先对(w,h)(w, h)(w,h)进行排序二分查询 hi<hh_i<hhi​<h的最大下标,找他的前缀最小值www(可以预处理)

AC代码

#include <bits/stdc++.h>
using namespace std;const int N = 200010;
const int INF = 0x3f3f3f3f;
class Node
{public:int h, w;int idx;void operator=(const Node &t1){h = t1.h, w = t1.w, idx = t1.idx;}
}a[N], q[N];
int pre_w[N], pre_idx[N];
int n;bool cmp(const Node &t1, const Node &t2)
{if (t1.h == t2.h)return t1.w < t2.w;elsereturn t1.h < t2.h;
}int Cal2(int h, int w)
{int l = 1, r = n, mid;if (h <= q[l].h)  return -1;while (l < r){mid = l + r + 1 >> 1;if (q[mid].h < h){l = mid;}else{r = mid - 1;}}if (w > pre_w[l])   // 找到了一个高度小,宽度也小的return pre_idx[l];else    // 没有宽度小的return -1;
}int Cal(int h, int w)
{int res1 = Cal2(h, w), res2 = Cal2(w, h);if (res1 == -1 && res2 == -1)return -1;elsereturn max(res1, res2);
}int main()
{int t;  cin >> t;while (t -- ){scanf("%d", &n);for (int i = 1; i <= n; i ++ ){scanf("%d%d", &a[i].h, &a[i].w);a[i].idx = i;q[i] = a[i];}sort(q + 1, q + 1 + n, cmp);pre_w[0] = INF, pre_idx[0] = -1;for (int i = 1; i <= n; i ++ ){if (q[i].w < pre_w[i - 1]){pre_w[i] = q[i].w, pre_idx[i] = q[i].idx;}else{pre_w[i] = pre_w[i - 1], pre_idx[i] = pre_idx[i - 1];}}/*for (int i = 1; i <= n; i ++ )printf("h=%d, w=%d, idx=%d, pre_w=%d, pre_idx=%d\n", q[i].h, q[i].w, q[i].idx, pre_w[i], pre_idx[i]);*/printf("%d", Cal(a[1].h, a[1].w));for (int i = 2; i <= n; i ++ ){printf(" %d", Cal(a[i].h, a[i].w));}puts("");}return 0;
}



F New Year’s Puzzle

原题信息

http://codeforces.com/contest/1472/problem/F

解题思路

首先第一个想到的就应该是对这些点按照列编号进行排序,然后我们逐个点进行处理。
用cur1,cur2cur1,cur2cur1,cur2表示当前第一行,第二行当前可以放置的最小列编号。下面我们对BlockedCellBlocked CellBlockedCell进行讨论

  • r1=r2r1 = r2r1=r2,即两个BlockedCellBlockedCellBlockedCell将一整列堵住,那么要求abs(cur1−cur2)abs(cur1-cur2)abs(cur1−cur2)%2=02=02=0,最后更新cur1=cur2=r1+1cur1=cur2=r1+1cur1=cur2=r1+1即可,这一次处理了两个BlockedCellBlockedCellBlockedCell问题
  • r1!=r2r1 != r2r1!=r2,我们处理BlockedCell(r1,c1)BlockedCell(r1, c1)BlockedCell(r1,c1),假设这个BlockedCellBlockedCellBlockedCell在cur1cur1cur1那一列。首先倘若r1<cur1r1<cur1r1<cur1指定不行,因为小于cur1cur1cur1的区域已经使用完毕
    那么如果(r1−cur2)(r1-cur2)(r1−cur2)%2=02=02=0,那么就说明这一行是可以自己解决的。
    即使是使用了下面的那一行,也会是成对的使用,与另外一列自己解决一样
    倘若(r1−cur2)(r1-cur2)(r1−cur2)%2=12=12=1,也就是说他需要另外一列的帮助,加奇数的竖线排列,下面我们只需考虑是否可以加(至少)一个竖线,在这里只需要考虑加一个就行,因为多加了也只能是奇数个,奇数个竖线,两两可以合并为横线,因为是加入一个,我们考虑一下最晚加入(在cur−1cur-1cur−1的位置)。
    为什么是最晚在cur−1cur-1cur−1?因为最晚就是在 BlockedCell之前加入!
    那么如何判断是否可以,那么只需在最晚加入的话,另一个列前方时候可以组成成对个二元组即可
    最后cur1,cur2cur1, cur2cur1,cur2注意更新,一个为c1c1c1,一个为c1+1c1 + 1c1+1
  • 最后,我们还需考虑满足了BlockedCellBlockedCellBlockedCell之后的cur1,cur2cur1, cur2cur1,cur2是否可以在结尾处ok,因此检验一下
    (cur1−cur2)(cur1-cur2)(cur1−cur2)%2=02=02=0->成立,否则不成立

AC代码

#include <bits/stdc++.h>
using namespace std;const int M = 200010, INF = 0x3f3f3f3f;
int n, m;class Node
{public:int r, c;
}q[M];bool cmp(const Node &t1, const Node &t2)
{if (t1.c == t2.c)return t1.r < t2.r;elsereturn t1.c < t2.c;
}bool Check()
{// if (m & 1)  return false;sort(q + 1, q + 1 + m, cmp);
/*for (int i = 1; i <= m; i ++ )printf("I=%d, r=%d, c=%d\n", i, q[i].r, q[i].c);
*/int r1, r2, c1, c2;int cur1 = 1, cur2 = 1;q[m + 1].c = INF;for (int i = 1; i <= m; i += 1){/// printf("I=%d, cur1=%d, cur2=%d\n", i, cur1, cur2);c1 = q[i].c, r1 = q[i].r, c2 = q[i + 1].c, r2 = q[i + 1].r;if (c1 == c2){/// puts("Equal");i ++;if (abs(cur1 - cur2) & 1)   // 口封不上return false;cur1 = cur2 = c1 + 1;}else{if (r1 == 1)    // 上面{/// puts("Up");if (cur1 > c1)  // 当前这个地方不能堵上return false;else{if ((c1 - cur1) % 2 == 0)   // 偶数,可以自行解决{cur1 = c1 + 1;}else    // 需要下面协助一个竖着的{cur1 = c1 - 1;if (cur1 - cur2 >= 0 && (cur1 - cur2) % 2 == 0)  // 下面可以跟上{cur1 = c1 + 1;cur2 = c1;}else{return false;}}}}else    // 下面{/// puts("Down");if (cur2 > c1)  // 当前这个地方不能堵上return false;else{if ((c1 - cur2) % 2 == 0)   // 偶数,可以自行解决{cur2 = c1 + 1;}else    // 需要上面协助一个竖着的{cur2 = c1 - 1;/*printf("Down, cur1=%d, cur2=%d\n", cur1, cur2);printf("%d\n", cur2 - cur1 >= 0);printf("%d\n", ((cur2 - cur1) % 2 == 0));*/if ((cur2 - cur1 >= 0) && ((cur2 - cur1) % 2 == 0))  // 上面可以跟上{cur2 = c1 + 1;cur1 = c1;}else{//puts("FALSE");return false;}}}}}}if (abs(cur1 - cur2) & 1)return false;elsereturn true;
}int main()
{int t;  cin >> t;while (t -- ){scanf("%d%d", &n, &m);for (int i = 1; i <= m; i ++ )scanf("%d%d", &q[i].r, &q[i].c);if (Check())puts("YES");elseputs("NO");}return 0;
}
/*
1
4 2
1 2
2 2
YES
*/
/*
1
4 3
1 1
1 2
2 2
NO
*/
/*
1
4 2
1 1
2 3
YES
*/
/*
3
5 2
2 2
1 4
3 2
2 1
2 3
6 4
2 1
2 3
2 4
2 6
*/



G Moving to the Capital

原题信息

http://codeforces.com/contest/1472/problem/G


解题思路

一个很有意思的dp问题
首先我们先利用bfs求出起点到其它任意各点的举例,然后我们进行dp求解。

  • dp思路一
    fi,0f_{i, 0}fi,0​表示从iii点开始,使用0次规则2可以达到的最小ddd,(其实就是自身的ddd)
    fi,1f_{i, 1}fi,1​表示从iii点开始,使用1次规则2可以达到的最小ddd
    下面我们来分析一下fi,1f_{i, 1}fi,1​如何进行更新,
    fi,1={fj,0∃i⇒j边且di≥djfj,1∃i⇒j边且di<djf_{i, 1}=\begin{cases} f_{j, 0} & \exists i \Rightarrow j 边且d_i\geq d_j\\ f_{j, 1} & \exists i \Rightarrow j 边且d_i < d_j\\ \end{cases}fi,1​={fj,0​fj,1​​∃i⇒j边且di​≥dj​∃i⇒j边且di​<dj​​
    fj,0f_{j, 0}fj,0​容易保证,因为直接就是djd_jdj​,但是我们如何保证使用的fj,1f_{j,1}fj,1​是更新完毕的最终结果呢? 下面我们考虑fj,1f_{j,1}fj,1​如何使其尽可能早的确定,而且不会使用到未确定的fj,1f_{j,1}fj,1​,我们从di,djd_i, d_jdi​,dj​在分段函数的关系中,就可以发现,倘若我们对ddd的距离进行降序排序,即先进性距离更大的dpdpdp,那么就可以是得使用到的fj,1f_{j,1}fj,1​都会是前面进行处理完毕的,因此进行dpdpdp的算法如下代码

  • Algo

  • 首先bfsbfsbfs处理出各点的距离did_idi​

  • 处理出did_idi​之后,我们就可以进行按照距离进行非递增排序。

  • 按照分段函数进行dpdpdp

AC代码

#include <bits/stdc++.h>
using namespace std;const int N = 200010, INF = 0x3f3f3f3f;
int f[N];
int h[N], e[N], ne[N], idx;
int n, m;
bool st[N];
int dist[N];
vector<int> order;void Initial()
{// edge initialmemset(h, -1, sizeof h);idx = 0;// dp initialmemset(f, 0x3f, sizeof f);// dist initialmemset(dist, -1, sizeof dist);// orderorder.clear();
}void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}int main()
{int t;  cin >> t;while (t -- ){// inputscanf("%d%d", &n, &m);// initialInitial();for (int i = 1, u, v; i <= m; i ++ ){scanf("%d%d", &u, &v);add(u, v);}// bfs for distqueue<int> que;que.push(1);    dist[1] = 0;order.push_back(1);int u, v;while (que.size()){u = que.front();    que.pop();for (int i = h[u]; ~i; i = ne[i]){v = e[i];if (dist[v] == -1){dist[v] = dist[u] + 1;que.push(v);order.push_back(v);}}}/*for (int i = 1; i <= n; i ++ )printf("i=%d dist=%d\n", i, dist[i]);*/// dfs for dp/*从距离最远的开始,进行枚举dp*/for (int j = n - 1, u, v; j >= 0; j -- ){u = order[j];f[u] = dist[u];for (int i = h[u]; ~i; i = ne[i]){v = e[i];if (dist[u] >= dist[v])  // u -> v 需要耗费一次机会, 只可以 取dist{f[u] = min(f[u], dist[v]);}else    // 不需要消耗机会,直接最优子结构{f[u] = min(f[u], f[v]);}}}// output/*for (int i = 1; i <= n; i ++ )printf("i=%d, f[i][0]=%d, f[i][1]=%d\n", i, f[i][0], f[i][1]);*/printf("%d", 0);for (int i = 2; i <= n; i ++ )printf(" %d", f[i]);puts("");}return 0;
}



Codeforces Round #693 (Div. 3)A~G解题报告相关推荐

  1. Codeforces Round #697 (Div. 3)A~G解题报告

    Codeforces Round #697 (Div. 3)A~G解题报告 题 A Odd Divisor 题目介绍 解题思路 乍一想本题,感觉有点迷迷糊糊,但是证难则反,直接考虑没有奇数因子的情况, ...

  2. Codeforces Round #697 (Div.3) A~G解题报告与解法证明

    题目大体概括 A #include <cstdio> #include <cstring> #include <algorithm> #include <io ...

  3. Codeforces Round #700 (Div. 2)A~D2解题报告

    Codeforces Round #700 (Div. 2)A~D2解题报告 A Yet Another String Game 原题链接 http://codeforces.com/contest/ ...

  4. Codeforces Round #830 (Div. 2) B. Ugu 解题报告

    原题链接: Problem - B - Codeforces 题目描述: A binary string is a string consisting only of the characters 0 ...

  5. 【Codeforces Round #570 (Div. 3) A-H 】解题报告

    cf570 cf570A 题意 一个数的数位和%4如果为 0 是我们要的答案 问加几次能使得他数位和 %4 为0 暴力即可 /*if you can't see the repayWhy not ju ...

  6. Codeforces Round #693 (Div. 3)部分题解

    Codeforces Round #693 (Div. 3) 部分题解 D. Even-Odd Game 思路: 贪心:田忌赛马 (1)先将数组从大到小排序,取数时从大到小取,用一个ans变量记录取数 ...

  7. Codeforces Round #701 (Div. 2)赛后补题报告(A~D)

    Codeforces Round #701 (Div. 2)赛后补题报告(A~D) A. Add and Divide 原题信息 http://codeforces.com/contest/1485/ ...

  8. Codeforces Round #827 (Div. 4) A~G

     比赛链接:Dashboard - Codeforces Round #827 (Div. 4) - Codeforces 目录 A Sum B Increasing C Stripes D. Cop ...

  9. Codeforces Round #693 (Div. 3)G. Moving to the Capital

    题目链接:Problem - G - Codeforces 题目大意:给定一张n个节点m条边的图,定义d数组为每个结点到结点1的距离. 每次可以选择两个操作:1,跳到结点x,dx>d当前 2.跳 ...

最新文章

  1. 小李飞刀:SQL题目第二弹!
  2. python实验报告代写价格_代写OS python程序作业、代写代写OS作业、代写OS实验报告...
  3. IntelliJ idea 中使用Git
  4. linuxpgrepgrep_linux命令:ps pstree pgrep pidof进程管理
  5. snmp v3的安全配置 snmp认证与加密配置(53)
  6. 一条长为L的绳子,一面靠墙,另外三边组成矩形,问此矩形最大面积能是多少?...
  7. python调整照片
  8. 列车座位应考虑向后摆放
  9. 服务器双硬盘系统安装系统安装,固态机械混合安装教程!双硬盘安装系统的方法...
  10. css背景颜色渐变 从左到右 从下到上
  11. FPGA | Vivado 查看最大工作频率(Fmax)
  12. SCI期刊最权威的信息查询步骤!
  13. 【引用】教你会看电脑的配置
  14. 大连首闻grid二次开发增强文档
  15. css view a if属性,uni-app学习笔记(2)view属性控制css样式
  16. 用树莓派做一个实时垃圾分类器|超实用!!
  17. 微信怎么转移聊天记录到另一台新手机,3个免费方法!
  18. java项目——防止羊毛党“薅羊毛”
  19. 酷友观点/经验:iphone 5\6\6p各尺寸参照图(原创)
  20. 计算机图形学 Unity ShaderLab 颜色混合运算相关计算方法

热门文章

  1. 现在中国是以24枚金牌位列奖牌榜3位,美国英国分列1、2位
  2. [hdu5372 Segment Game]树状数组
  3. Git 常用命令整理(持续更新)
  4. 安装“消息队列 (MSMQ)”
  5. 一文让你了解RT-Thread
  6. 同事用void把我给秀翻了!
  7. 解析一个C语言俄罗斯方块游戏,包你看了就会
  8. 工作4年工资8K,还有什么理由不努力?
  9. VC6.0常见英文错误对照表
  10. 怎么撤回操作_微信又更新,拍一拍能撤回了