Contest Info


[Practice Link](https://codeforc.es/contest/1202)

Solved A B C D E F
5/6 Ø Ø Ø Ø Ø -
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


A. You Are Given Two Binary Strings...

题意:

给出两个数字\(x, y\),令\(f(x)\)为\(x\)的二进制表示,现在要选择一个\(k\)使得\(s_k = f(x) + f(y) \cdot 2^k\)的字典序最小。

思路:

考虑乘上\(2^k\)相当于让\(f(y)\)左移\(k\)位,那么我们肯定要让\(f(y)\)的最后一位\(1\)移到离\(f(x)\)最近的一个\(1\)和它进位之后,这样翻转之后字典序是最小的。

view code

#include <bits/stdc++.h>
using namespace std;

define N 100010

char s[N], t[N]; int main() {

int T; scanf("%d", &T);

while (T--) {

scanf("%s%s", s + 1, t + 1);

int lens = strlen(s + 1);

int lent = strlen(t + 1);

int post = 0;

for (int i = lent; i >= 1; --i) {

if (t[i] == '1') {

post = lent - i;

break;

}

}

int res = 0;

for (int i = lens - post; i >= 1; --i) {

if (s[i] == '1') {

res = lens - post - i;

break;

}

}

printf("%d\n", res);

}

return 0;

}

B. You Are Given a Decimal String...

题意:

有\(x-y\)计数器,它是这样工作的:

  • 初始时数值为\(0\)
  • 给数值加上\(x\)或者\(y\),然后输出数值模\(10\)后的结果
  • 重复第二步操作,直到输出自己满意的序列

    现在给定一段序列,问对于\(x \in [0, 9], y \in [0, 9]\)的\(100\)种计数器,最少需要增加多少数才能使得输出的序列是x-y$计数器合法输出来的?

思路:

考虑对于序列中间隔的两个数\(s[i]\)和\(s[i + 1]\),我们定义它们之间的差值为\((s[i + 1] - s[i] + 10) \% 10\),因为是数值的最后一位,所以它们的真实差距肯定可以写成\(10k + (s[i + 1] - s[i])\),但是我们并不需要关心\(k\)是多少。

我们只需要知道需要多少个\((px + qy) \% 10 = (s[i + 1] - s[i] + 10) \% 10\)。

这个暴力枚举一下\(p, q\)即可,而显然\(p \in [0, 9], q \in [0, 9]\),因为存在模\(10\)操作,\((px + qy) \% 10 = (p \% 10 x + q \% 10 ) \% 10\)

view code

#include <bits/stdc++.h>
using namespace std; const int INF = 0x3f3f3f3f;

const int N = 2e6 + 10;

char s[N];

int n, b[20];

void Min(int &x, int y) {

if (x > y) x = y;

} int main() {

while (scanf("%s", s + 1) != EOF) {

n = strlen(s + 1);

for (int x = 0; x < 10; ++x) {

for (int y = 0; y < 10; ++y) {

for (int k = 0; k < 10; ++k) b[k] = INF;

for (int p = 0; p < 10; ++p) {

for (int q = 0; q < 10; ++q) if (p | q) {

Min(b[(p * x + q * y) % 10], p + q - 1);

}

}

int ans = 0;

for (int i = 1; i < n; ++i) {

int t = (s[i + 1] - s[i] + 10) % 10;

if (b[t] == INF) {

ans = -1;

break;

}

ans += b[t];

}

printf("%d%c", ans, " \n"[y == 9]);

}

}

}

return 0;

}

C. You Are Given a WASD-string...

题意:

有一个机器人,现在给出一系列行走步骤,问能否在任意处添加一个步骤,使得它的行动范围尽量小。

行动范围的定义为用一个最小的矩形框住它的行动路径。范围即为矩形的面积。

思路:

将横竖分开考虑,如果可以缩小行动范围,那么必然是长缩短一或者宽缩短一。

我们考虑什么时候边长可以缩短一:

  • 考虑从一个位置插入一个状态,那么考虑从从这个点之后的所有这个方向的路径都会整体往上移动一个或者往下移动一个
  • 那么判断一下这个移动是否有效即可。
  • 有效的定义为这个点之后的路径的最值比这个点以及之前的最值大,这样它的最值才会减一,不然的话这个点以及之前的最值仍然掌控着矩形边界
view code

#include <bits/stdc++.h>
using namespace std;

define ll long long

define N 200010

char s[N]; int main() {

int T; scanf("%d", &T);

while (T--) {

scanf("%s", s + 1);

int n = strlen(s + 1);

int nowx = 0, nowy = 0;

int up = 0, down = 0, left = 0, right = 0;

int gup = 0, gdown = 0, gleft = 0, gright = 0;

for (int i = 1; i <= n; ++i) {

if (s[i] == 'W') --nowx;

if (s[i] == 'S') ++nowx;

if (s[i] == 'A') --nowy;

if (s[i] == 'D') ++nowy;

up = min(up, nowx);

down = max(down, nowx);

left = min(left, nowy);

right = max(right, nowy);

gup = max(gup, nowx - up);

gdown = max(gdown, down - nowx);

gleft = max(gleft, nowy - left);

gright = max(gright, right - nowy);

}

ll x[2], y[2];

x[0] = max(gup, gdown);

x[1] = max(1ll * (gup || gdown), x[0] - (gup != gdown));

y[0] = max(gleft, gright);

y[1] = max(1ll * (gleft || gright), y[0] - (gleft != gright));

printf("%lld\n", min((x[0] + 1) * (y[1] + 1), (x[1] + 1) * (y[0] + 1)));

}

return 0;

}

D. Print a 1337-string...

题意:

构造一个序列,这个序列只包含\(\{1, 3, 7\}\),并且一共有\(n\)的子序列是\(1337\)

思路:

考虑最后一位放\(7\)。

然后放\(x\)个\(3\)。

那么每放一个\(1\)可以产生\([1, \frac{x(x - 1)}{2}]\)个\(1337\)。

那么考虑从大到小贪心放即可,总能放完。

view code

#include <bits/stdc++.h>
using namespace std;

define ll long long

define N 100010

ll n;

ll f(ll x) {

return x * (x - 1) / 2;

} int main() {

int T; scanf("%d", &T);

while (T--) {

scanf("%lld", &n);

for (int i = 32000; i >= 2; --i) {

while (f(i) <= n) {

n -= f(i);

putchar('1');

}

putchar('3');

}

assert(n == 0);

puts("37");

}

return 0;

}

E. You Are Given Some Strings...

题意:

给出一个文本串\(T\),和若干个模式串\(S_i\),定义\(f(t, s)\)为\(s\)在\(t\)中出现的次数。

计算下式:

\[\begin{eqnarray*}
\sum\limits_{i = 1}^n \sum\limits_{j = 1}^n f(t, s_i + s_j)
\end{eqnarray*}
\]

思路:

考虑\(T\)对整体的贡献,即使\(T\)中存在多少个子串,使得可以从某个中间位置切开,使得左右两边都是模式串。

那么枚举这个中间位置即可,做两边\(AC\)自动机,求出\(f[i], g[i]\),分别表示以\(i\)结尾的模式串匹配次数和以\(i\)开头的模式串匹配次数。

那么乘一乘即是结果。

view code

#include <bits/stdc++.h>
using namespace std;

define ll long long

define N 200010

int n;

string s[N], t, tr;

ll f[N], g[N];

define ALP 26

struct ACAM {

struct node {

int nx[ALP], fail;

int cnt;

node() {

memset(nx, -1, sizeof nx);

cnt = 0;

}

}t[N];

int root, tot;

int que[N], ql, qr;

//节点从1开始

int newnode() {

++tot;

t[tot] = node();

return tot;

}

void init() {

tot = 0;

root = newnode();

}

void insert(string s) {

int len = s.size();

int now = root;

for (int i = 0; i < len; ++i) {

if (t[now].nx[s[i] - 'a'] == -1)

t[now].nx[s[i] - 'a'] = newnode();

now = t[now].nx[s[i] - 'a'];

}

++t[now].cnt;

}

void build() {

ql = 1, qr = 0;

t[root].fail = root;

for (int i = 0; i < ALP; ++i) {

if (t[root].nx[i] == -1) {

t[root].nx[i] = root;

} else {

t[t[root].nx[i]].fail = root;

que[++qr] = t[root].nx[i];

}

}

while (ql <= qr) {

int now = que[ql++];

t[now].cnt += t[t[now].fail].cnt;

for (int i = 0; i < ALP; ++i) {

if (t[now].nx[i] == -1) {

t[now].nx[i] = t[t[now].fail].nx[i];

}

else {

t[t[now].nx[i]].fail = t[t[now].fail].nx[i];

que[++qr] = t[now].nx[i];

}

}

}

}

void query(string s, ll *f) {

int len = s.size();

int now = root;

for (int i = 0; i < len; ++i) {

now = t[now].nx[s[i] - 'a'];

f[i] = t[now].cnt;

}

}

}ac; int main() {

ios::sync_with_stdio(false);

cin.tie(0); cout.tie(0);

while (cin >> t) {

tr = t; reverse(tr.begin(), tr.end());

cin >> n;

ac.init();

for (int i = 1; i <= n; ++i) cin >> s[i], ac.insert(s[i]);

ac.build();

ac.query(t, f);

ac.init();

for (int i = 1; i <= n; ++i) {

reverse(s[i].begin(), s[i].end());

ac.insert(s[i]);

}

ac.build();

ac.query(tr, g);

ll res = 0;

int len = t.size();

reverse(g, g + len);

for (int i = 0; i < len - 1; ++i) {

res += f[i] * g[i + 1];

}

cout << res << "\n";

}

return 0;

}

最新文章

  1. BPM配置故事之案例5-必填与水印文本
  2. Android开发环境搭建中的一些小问题记录
  3. iOS:音频
  4. tangent space /handness
  5. Java RMI之介绍
  6. oracle10g遇到ORA-00257归档程序错误,在释放之前仅限于内部连接
  7. 极光推送,极光IM使用指南(AndroidStudio)
  8. 函数返回值 return
  9. 【转】构建基于CXF的WebService服务
  10. python 自定义回调函数
  11. SQL语句的CRUD
  12. Distance on the tree(数剖 + 主席树)
  13. redis学习总结-redis作为MyBatis的自定义缓存
  14. 内省(Introspector)
  15. 34-ssm 最简洁的模板
  16. HTML DOM item() 方法
  17. HackerRake平台说明和介绍
  18. AngularJS---核心特性
  19. Vue的路由
  20. Markdown中添加数学公式

热门文章

  1. TZOJ5201: 数字游戏
  2. [PKUSC2018]主斗地(搜索+贪心)
  3. apply,call和bind的使用及区别
  4. hdu 1075 map的使用 字符串截取的常用手段 以及string getline 使用起来的注意事项
  5. centos7 安装jdk及mysql8
  6. Linux之mysql的安装与,主从设置
  7. Python基础Day6
  8. linux安装zookeeper,安装zkui,zookeeper可视化
  9. 解决mybatis实体类和数据库列名不匹配的两种办法
  10. 开源框架---tensorflow c++ API 运行第一个“手写字的例子”