转载自:https://lornd.top/index.php/archives/9/

比赛地址:AtCoder Beginner Contest 135

A - Harmony

题目大意:给你两个数 \(A\) 和 \(B\) ,是否存在一个整数 \(K\) 使得 \(|A - K| = |B - K|\) 。

解题思路:显然 \(K = \frac{A + B}{2}\) 。那么当 \(A\) 和 \(B\) 奇偶性不同时,\(K\) 就不存在。

#include <cstdio>int a, b;int main() {scanf("%d%d", &a, &b);if ((a - b) & 1)printf("IMPOSSIBLE");elseprintf("%d", (a + b) >> 1);return 0;
}

B - 0 or 1 Swap

题目大意:给你一个 \(1 \sim n\) 的排列,是否可以通过一次对这个排列中的某两个元素的交换来使得这个排列是递增的。

解题思路:因为这个序列是 \(1 \sim n\) 的排列,所以当这个排列是递增的的时候,必然有 \(a_i = i\ (i \in [1,n])\) 。因此我们仅需统计有多少个 \(i\) 满足 \(a_i \neq i\) 即可,若大于两个,则无法满足题意。

#include <cstdio>const int MAXN = 55;int n, cnt;
int arr[MAXN];int main() {scanf("%d", &n);for (int i = 1; i <= n; ++i) {scanf("%d", &arr[i]);if (arr[i] != i)++cnt;}if (cnt > 2)printf("NO");elseprintf("YES");return 0;
}

C - City Savers

题目大意:有 \(n\) 个城市,第 \(i\) 个城市有 \(A_i\) 个怪物和一个勇士,在第 \(i\) 个城市的勇士可以消灭第 \(i\) 和 \(i + 1\) 个城市的怪物共 \(B_i\) 个,问最多能消灭多少个怪物。

解题思路:简单贪心,因为下一个城市的怪物就算自己消灭不了,下一个城市的勇士也会去尽可能消灭,所以就先消灭完自己城市的怪物再去帮助下一个城市。

#include <cstdio>typedef long long int ll;const int MAXN = 1e5 + 5;int n;
ll ans;
ll A[MAXN], B[MAXN];int main() {scanf("%d", &n);for (int i = 1; i <= n + 1; ++i) {scanf("%lld", &A[i]);}for (int i = 1; i <= n; ++i) {scanf("%lld", &B[i]);if (B[i] <= A[i])ans += B[i];else if (B[i] <= A[i] + A[i + 1]) {ans += B[i];A[i + 1] -= (B[i] - A[i]);}else {ans += (A[i] + A[i + 1]);A[i + 1] = 0;}}printf("%lld", ans);return 0;
}

D - Digits Parade

题目大意:给你一个字符串 \(s\) ,由 \(0 \sim 9\) 和 \(?\) 组成,每个 \(?\) 处可以填入 \(0 \sim 9\) 这是个数字,将所有数字填完之后,可以得到一个整数,问由多少种填法,使得这个数模 \(13\) 余 \(5\) 。

解题思路:因为我们有以下定理:若 \(a\ Mod\ x = i,\ b\ Mod\ x = j,\ c\ Mod\ x = k\) ,那么 \((a \times b + c)\ Mod\ x = (i \times j + k)\ Mod\ x\) 。所以我们如果知道了一个数模 \(13\) 的余数,我们也能很快知道在这个数后面加上一个数字(将这个数乘 \(10\) 再加上一个一位数)模 \(13\) 的余数,所以我们假设 \(dp[i][j]\) 表示 考虑到第 \(i\) 位,前面能组成模 \(13\) 余 \(j\) 的方案数,从前往后模拟这个过程即可,因为 \(j\) 很小,所以这个算法的复杂度可以认为是 \(\Theta(n)\) 。

#include <cstdio>
#include <cstring>const int MAXN = 1e5 + 5;
const int mod = 1e9 + 7;int len;
int dp[MAXN][13];
char s[MAXN];int main() {scanf("%s", s + 1);len = strlen(s + 1);dp[0][0] = 1;for (int i = 1; i < 13; ++i) {dp[0][i] = 0;}for (int i = 0; i < len; ++i) {for (int j = 0; j < 13; ++j) {if (s[i + 1] != '?') {int tmp = s[i + 1] - '0';dp[i + 1][(j * 10 + tmp) % 13] += dp[i][j];if (dp[i + 1][(j * 10 + tmp) % 13] > mod)dp[i + 1][(j * 10 + tmp) % 13] -= mod;}else {for (int k = 0; k <= 9; ++k) {dp[i + 1][(j * 10 + k) % 13] += dp[i][j];if (dp[i + 1][(j * 10 + k) % 13] > mod)dp[i + 1][(j * 10 + k) % 13] -= mod;}}}}printf("%d", dp[len][5]);return 0;
}

E - Golf

题目大意:有一个球在点 \((0,0)\) ,要到点 \((x,y)\) 去。每次只能移动到与其所在点曼哈顿距离为 \(k\) 的点,问是否能到达点 \((x,y)\) ,若能,最少需要移动多少次?

解题思路:来自:Geothermal(红名)

由于平面直角坐标系的对称性,不失一般性地,我们认为点 \((x,y)\) 在第一象限,若在其他象限,只需对 \(x,y\) 进行乘 \(-1\) 或 \(1\) 的变换即可。我们假设最少需要移动 \(n\) 次,其中正向移动(向着 \(x\) 轴和 \(y\) 轴的正方向移动)的距离为 \(a\) ,反向移动的距离为 \(b\) 。那么显然会有 \(a + b = nk\) 且 \(a - b = x + y\) ,可以解得 \(a = \frac{nk + x + y}{2}, b = \frac{nk - x - y}{2}\)。

因为 \(a,b\) 均为非负整数,所以我们可以得到三个结论:

  1. 如果 \(k\) 是偶数而 \(x + y\) 是奇数,那么一定不能到达,因为在这种话情况下无论 \(n\) 为多少,\(nk\) 均为偶数,\(nk \pm (x + y)\) 是奇数, \(a,b\) 均不是整数。

  2. 一定存在 \(nk \ge x + y\) 且 \(nk \equiv (x + y)\ (Mod\ 2)\) ,前者是因为 \(b\) 的非负性,而后者是因为 \(a,b\) 要是整数。

  3. 如果 \(n = 1\) ,那么一定要 \(k = x + y\) ,这十分显然,因为如果点 \((x,y)\) 与点 \((0,0)\) 的曼哈顿距离不是 \(k\) ,那么肯定不能一步到达。

根据结论 \(1\) ,我们就可以判断出无解的情况了,接下来我们构造出结论 \(2, 3\) 所述情况的方法。

首先 \(n\) 可以暴力求出来,然后便可以算出 \(a\) 和 \(b\) 。接下来我们先考虑反向移动,如果剩余反向移动的距离大于 \(k\) ,那么就在某一个方向上反向移动 \(k\) ,否则移动剩余的反向移动距离,在另一个方向上正向移动。接下来考虑正向移动,这个就可以随便移了,可以先让 \(x\) 到位再竖直移动,也可以先让 \(y\) 到位再水平移动,但最后总是可以到达 \((x,y)\) 这个点。

注意:反向移动所说的 “某一个方向” 指的都是在当前位置与目标地点更近的方向(不考虑另外一个方向的距离),即 \(min(|x_1 - x_2|, |y_1 - y_2|)\) 所对应的距离。

#include <cstdio>typedef long long int ll;int n, x, y, flagX, flagY, curX,  curY;
ll k, positive, negative;int main() {scanf("%lld%d%d", &k , &x, &y);flagX = (x < 0) ? -1 : 1;flagY = (y < 0) ? -1 : 1;x *= flagX;y *= flagY;if (k % 2 ==0 && (x + y) & 1)printf("-1");else {if (k == x + y)n = 1;else {n = 2;while (n * k < x + y || (n * k - x - y) & 1) {++n;}}positive = (n * k + x + y) >> 1;negative = (n * k - x - y) >> 1;printf("%d\n", n);while(n --) {if (negative) {if (negative >= k) {if (x - curX <= y - curY)curX -= k;elsecurY -= k;negative -= k;}else {if (x - curX <= y - curY) {curX -= negative;curY += (k - negative);}else {curY -= negative;curX += (k - negative);}negative = 0;}}else {if (curX < x) {if (x - curX >= k)curX += k;else {curY += (k - (x - curX));curX = x;}}else {if (y - curY * flagY >= k)curY += k;elsecurY = y;}}printf("%d %d\n", curX * flagX, curY * flagY);}}return 0;
}

F - Strings of Eternity

题目大意:给定两个字符串 \(S\) 和 \(T\) ,找出最大的 \(i\) ,使得存在一个 \(j\) ,使得将 \(T\) 重复 \(i\) 次后得到的字符串是将 \(S\) 重复 \(j\) 次后所得的字符串的子串。显然,对于任何情况,总存在 \(i = 0\) 满足上述条件,若不存在最大的 \(i\) ,输出 \(-1\) 。

解题思路:来自:Geothermal(红名)

我们可以认为 \(j\) 是无限大,因为我们不断重复字符串 \(S\) 的过程中, \(i\) 只有可能越变越大,而不会越变越小。

因此,我们只需要找到这个无限长的字符串中所有与 \(T\) 匹配的子串,并找出最长的连续的多个子串即可。

我们发现:两个子串连续,假设它们的开头的下标分别为 \(p_1,p_2\ (p_1 < p _2)\) ,则一定有 \(p_1 + | T | = p_2\) 。因此我们如果可以找到所有子串的开头,再依照这个关系将所有开头连成一个图,问题就会被我们转化成一个有向图的最长路问题。

我们如何找到这些开头呢?因为 \(S\) 串是不断重复的,所以开头看起来有无数个,但事实上都可以映射到 \([1,| S |]\) 中,所以我们只需找到 \([1, |S|]\) 中所有的开头即可,为了保证所有的开头都能够被找到,我们只需不断重复 \(S\) 串,直到其长度大于最初的 \(|S| + |T|\) ,再对新的 \(S\) 串和 \(T\) 串进行 KMP 匹配即可。

在找到所有开头之后,下一步就是建图了,根据我们的发现,我们把所有开头的下标抽象成一个个点,在两个点之间连边,当且仅当两个下标在模 \(|S|\) 的意义下相差 \(|T|\) 。即 \(j\ Mod\ |S| = (i + |T|)\ Mod\ |S|\) ,前提是 \(i,j\) 均为我们所说的开头,这个时候,就连一条边,从 \(i\) 指向 \(j\) 。

接下来是寻找最长路,这就是一个经典题目了,拓扑排序 + DP 即可完成,但需要特判有环的情况,这也同样可以使用拓扑排序完成,只要完成拓扑排序之后,被排序的点的数量小于开头的总数,图中便一定有环,此时答案就是 \(-1\) ,否则答案就是最长路的长度 。

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>const int MAXN = 5e5 + 5;char s[MAXN << 2], t[MAXN];
int lenS, lenT, copyLenS, copyLenT, ans;
int next[MAXN], sum;
int entry[MAXN], res[MAXN], dp[MAXN];
bool find[MAXN << 2];std::vector<int> con[MAXN];
std::queue<int> q;void init() {int place = 0;next[1] = 0;for (int i = 2; i <= lenT; ++i) {while (place && t[i] != t[place + 1]) {place = next[place];}if (t[i] == t[place + 1])++place;next[i] = place;}
}void kmp() {init();int place = 0;for (int i = 1; i <= lenS; ++i) {while(place && s[i] != t[place + 1]) {place = next[place];}if (s[i] == t[place + 1])++place;if (place == lenT && i - lenT + 1 <= copyLenS) {find[i - lenT + 1] = true;place = next[place];++sum;}}
}void ins(int start,int end) {con[start].push_back(end);++entry[end];
}bool topSort() {int cnt = 0;for (int i = 1; i <= copyLenS; ++i) {if (find[i] && entry[i] == 0)q.push(i);}while (!q.empty()) {int cur = q.front();res[++cnt] = cur;for (int i = 0; i < con[cur].size(); ++i) {if (--entry[con[cur][i]] == 0)q.push(con[cur][i]);}q.pop();}return cnt == sum;
}int main() {scanf("%s%s", s + 1, t + 1);copyLenS = lenS = strlen(s + 1);copyLenT = lenT = strlen(t + 1);while (copyLenT > 0) {for (int i = 1; i <= copyLenS; ++i) {s[++lenS] = s[i];}copyLenT -= copyLenS;}kmp();for (int i = 1; i <= copyLenS; ++i) {int k = ((i + lenT) % copyLenS == 0) ? copyLenS : ((i + lenT) % copyLenS);if (find[i] && find[k])ins(i, k);}if (topSort()) {for (int k = 1; k <= sum; ++k) {int i = res[k];if (dp[i] == 0)dp[i] = 1;for (int j = 0; j < con[i].size(); ++j) {dp[con[i][j]] = std::max(dp[con[i][j]], dp[i] + 1);}}for (int i = 1; i <= sum; ++i) {ans = std::max(ans, dp[res[i]]);}}elseans = -1;printf("%d", ans);return 0;
}

转载于:https://www.cnblogs.com/lornd/p/11302464.html

AtCoder Beginner Contest 135 解题报告相关推荐

  1. Atcoder Beginner Contest 124 解题报告

    心态爆炸.本来能全做出来的.但是由于双开了Comet oj一个比赛,写了ABC就去搞那个的B题 还被搞死了. 回来写了一会D就过了.可惜比赛已经结束了.真的是作死. A - Buttons #incl ...

  2. AtCoder Beginner Contest 132 解题报告

    前四题都好水.后面两道题好难. C Divide the Problems #include <cstdio> #include <algorithm> using names ...

  3. AtCoder Beginner Contest 285解题报告

    A - Edge Checker 2 Problem Statement Determine if there is a segment that directly connects the poin ...

  4. Atcoder Beginner Contest 260D - Draw Your Cards 解题报告

    Atcoder Beginner Contest 260D - Draw Your Cards 解题报告 1 题目链接 abc260_d 2 题目大意 题目 : 抽牌 题目大意 : 给定NNN个数字, ...

  5. AtCoder Beginner Contest 300G - P-smooth number解题报告

    AtCoder Beginner Contest 300G - P-smooth number解题报告 1 题目链接 传送门 2 题目大意 题目:P-光滑数的数量 题目大意: 在 1 1 1 到 n ...

  6. AtCoder题解 —— AtCoder Beginner Contest 182 —— D - Wandering

    题目相关 题目链接 AtCoder Beginner Contest 182 D 题,https://atcoder.jp/contests/abc182/tasks/abc182_d. Proble ...

  7. AtCoder题解 —— AtCoder Beginner Contest 187 —— B - Gentle Pairs —— 暴力

    题目相关 题目链接 AtCoder Beginner Contest 187 B 题,https://atcoder.jp/contests/abc187/tasks/abc187_b. Proble ...

  8. AtCoder题解—— AtCoder Beginner Contest 181 —— B - Trapezoid Sum

    题目相关 题目链接 AtCoder Beginner Contest 181 B 题,https://atcoder.jp/contests/abc181/tasks/abc181_b. Proble ...

  9. AtCoder Beginner Contest 282 A-E

    比赛名称:HHKB Programming Contest 2022 Winter(AtCoder Beginner Contest 282) 比赛链接:AtCoder Beginner Contes ...

  10. AtCoder Beginner Contest 202 D - aab aba baa(组合计数,字典序)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Problem 有 AAA 和 aaa,BBB 个 bbb ,可以使用这 A+BA+BA+B 个字符任 ...

最新文章

  1. 领域驱动设计(DDD)架构演进和DDD的几种典型架构介绍(图文详解)
  2. SAP HUM事务代码HUMO里显示内层和外层HU信息
  3. 利用JDK动态代理机制实现简单拦截器
  4. iOS之一个iOS开发人员完整的学习路线
  5. hdfs写数据流程分析
  6. boost库 数组智能指针scoped_array
  7. vue 引入json地图_VUE中通过Echarts引入地图
  8. word制作电子签名
  9. can总线报文是固定的吗_CAN总线传输协议
  10. 从零学ELK系列(一):为什么要跟我学从零学ELK系列
  11. 一大波DeepMind专利来袭,AI圈瑟瑟发抖:连RNN都是你家的?
  12. Delphi中怎么结束线程(这个线程是定时执行的)(方案一)
  13. 苹果Mac好用的SSH连接客户端工具:​​​​​​​​​​​​Termius
  14. 第一章 数字图像基础
  15. 点云数据格式及处理工具
  16. PID控制算法的c语言实现 附录2 直流电机PWM调速系统中控制电压非线性研究
  17. android intent singletask,android – launchMode =“singleTask”不会创建新任务
  18. 【noi.ac #1779】D
  19. 中国首次包揽2021年国际信息学奥赛(IOI 2021)前四名
  20. 输入数据练习-JAVA

热门文章

  1. 在java中获取当前系统时间 插入数据库中的时间值没有时间只有日期的原因...
  2. BGP选路规则和负载分担
  3. 第 10 章 容器监控 - 080 - Weave Scope 容器地图
  4. IDEA 中git使用非默认ssh客户端进行登录
  5. SpringBoot+Shiro学习(七):Filter过滤器管理
  6. 云桌面三大谎言之GPU虚拟化
  7. java定义一个二维数组
  8. springboot 项目 测试环境在独立的tomcat部署
  9. 苹果之父乔布斯:我是如何东山再起的
  10. Java HashSet和LinkedHashSet的用法