比赛链接https://codeforc.es/contest/1202

 

A. You Are Given Two Binary Strings...

题意:给出两个二进制数\(f(x)\)和\(f(y)\),定义一个二进制数\(s_k=f(x)+2^k\cdot f(y)\),询问\(k\)取何值时\(s_k\)的反向字符串(将二进制数看作01串)字典序最小。

分析:首先,我们需要知道对于一个二进制数乘2,相当于将该数整体左移一位,因此我们只需要找到\(f(y)\)最右侧的1的位置\(pos\),令它去和\(f(x)\)在\(pos\)左侧最近的\(y\)匹配,这样得到的反向字符串字典序必然最小。

AC代码

#include <bits/stdc++.h>
#define SIZE 200007
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
ll n, m, t;
string s1, s2;
int main() {
io(); cin >> t;
while(t--) {
cin >> s1 >> s2;
int len1 = s1.length() - 1, len2 = s2.length() - 1;
n = 0;
while(s2[len2--] == '0') ++n;
m = n;
while(s1[len1 - m] == '0') ++m;
cout << m - n << endl;
}
}

 

B. You Are Given a Decimal String...

题意:不是很讲得清楚,可以看题中样例理解。给出一个字符串字符串中的每一位数字由确定的两个数字任意组合得到,询问,为了得到该字符串,最少需要多构成几个无效数字。例如:

给出字符串\(0840\),确定的两个数字为\((2, 4)\)。

  1. 0 (初始必定为零)
  2. 04 (\(+4\))
  3. 048 (\(+4\))
  4. 0482 (\(+4\),如果超过10就只取个位数)
  5. 04824 (\(+2\))
  6. 048248 (\(+4\))
  7. 0482480 (\(+2\))

于是,(0) 4 (8) 2 (4) 8 (0),多生成的数的个数为3。

分析:从字符串第\(k\)位到\(k+1\)位实际上相当于变化了\(\vert s_{k+1}-s_k \vert\),这个值不会超过10,因此我们只需要暴力求出这10种情况所生成的无效数字个数即可。

AC代码

#include <bits/stdc++.h>
#define SIZE 200007
#define rep(i, a, b) for(int i = a; i <= b; ++i)
const int maxn = 1e9;
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
int n, m, t; int dp[10];
string s;
int main() {
io(); cin >> s;
int len = s.length();
rep(i, 0, 9) {
rep(j, 0, 9) {
rep(k, 0, 9) dp[k] = maxn;
rep(x, 0, 9) {
rep(y, 0, 9) {
if (!x && !y) continue;
dp[(x * i + y * j) % 10] = min(x + y - 1, dp[(x * i + y * j) % 10]);
}
}
int ans = 0;
rep(k, 0, len - 2) {
int tmp = s[k + 1] - s[k];
if (dp[(tmp + 10) % 10] == maxn) { ans = -1; break; }
ans += dp[(tmp + 10) % 10];
}
cout << ans << ' ';
}
cout << endl;
}
}

 

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

题意:T组输入,每组输入给出一个只含“\(W, A, S, D\)”的字符串(又是字符串...)。\(W, A, S, D\)分别代表一个机器人可以向上,左,下,右四个方向移动一格。定义机器人走过的面积为能包含所有机器人走到过的格子的最小面积。现在,你能在字符串中的任意位置加入一个字符(只能为\(W, A, S, D\)),询问可能的机器人走过的最小面积。

分析:由于只能加入一个字符,所以我们发现横向的移动和纵向移动互不干扰(最小矩形只能是长或者宽缩进一个单位),因此我们只需要分成横向纵向两个子问题考虑,并找到最小面积即可。我用了一种前缀和的思想写,而标程给出了更简洁的解法。

AC代码

#include <bits/stdc++.h>
#define SIZE 200007
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
int n, m, t;
string str;
struct node {
int val;
int pos;
int la, lb, ra, rb;
}p1[SIZE], p2[SIZE];
void init1(node p[], int n) {
int x = INF, y = -INF;
rep(i, 0, n) {
p[i].la = min(x, p[i].pos);
x = min(x, p[i].la);
p[i].ra = max(y, p[i].pos);
y = max(y, p[i].ra);
}
}
void init2(node p[], int n) {
int x = INF, y = -INF;
for (int i = n; i >= 0; --i) {
p[i].lb = min(x, p[i].pos);
x = min(x, p[i].lb);
p[i].rb = max(y, p[i].pos);
y = max(y, p[i].rb);
}
}
int main() {
io(); cin >> t;
while (t--) {
cin >> str;
int k = 1, j = 1;
rep(i, 0, str.length() - 1) {
if (str[i] == 'W') p1[k++].val = 1;
else if (str[i] == 'S') p1[k++].val = -1;
else if (str[i] == 'A') p2[j++].val = 1;
else p2[j++].val = -1;
}
rep(i, 0, k - 1) p1[i].pos = p1[i - 1].pos + p1[i].val;
rep(i, 0, j - 1) p2[i].pos = p2[i - 1].pos + p2[i].val;
init1(p1, k - 1); init1(p2, j - 1);
init2(p1, k - 1); init2(p2, j - 1);
ll w = p1[k - 1].ra, a = p2[j - 1].la, s = p1[k - 1].la, d = p2[j - 1].ra;
ll h = p1[k - 1].ra - p1[k - 1].la + 1, wid = p2[j - 1].ra - p2[j - 1].la + 1;
bool f1 = false, f2 = false;
rep(i, 0, k - 1) {
if (p1[i].lb < p1[i].la && p1[i].rb < p1[i].ra) { f1 = true; break; }
if (p1[i].lb > p1[i].la && p1[i].rb > p1[i].ra) { f1 = true; break; }
}
rep(i, 0, j - 1) {
if (p2[i].lb < p2[i].la && p2[i].rb < p2[i].ra) { f2 = true; break; }
if (p2[i].lb > p2[i].la && p2[i].rb > p2[i].ra) { f2 = true; break; }
}
if (f1 || f2) {
if (f1 && f2) {
if (wid > h) cout << wid * (h - 1) << endl;
else cout << (wid - 1) * h << endl;
continue;
}
if (f1) cout << wid * (h - 1) << endl;
else cout << (wid - 1) * h << endl;
}
else cout << wid * h << endl;
}
}

 

D. Print a 1337-string...

题意:给出一个正整数\(n\),构造一个含有\(n\)个\(1337\)子串的字符串(还是字符串...)。

分析:我们考虑每次构造\(C_n^2\)个直到完成例如 \(10=6+3+1\),那么我们就能构造出\(13373737\)。但要注意最后可能会剩下2,可是不能重复构造两次1。因此最后为2的构造我们在倒数第三位插入两个1,例如:\(8=6+2\) 构造出:\(13311337\)。

AC代码

#include <bits/stdc++.h>
#define SIZE 200007
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
ll n, m, t; bool flag;
ll dp[SIZE];
vector<int> v;
int main() {
io(); cin >> t;
rep(i, 1, 100050) dp[i] = 1ll * i * (i - 1) / 2;
while (t--) {
cin >> n; m = n; v.clear();
if (n == 2) { cout << "11337\n"; continue; }
flag = false;
while (n) {
int pos = lower_bound(dp, dp + 100010, n) - dp;
if (dp[pos] > n) --pos;
n -= dp[pos];
v.emplace_back(pos);
if (n == 2) { flag = true; break; }
}
int cnt = 1, it = v.size() - 1;
cout << "13";
while (cnt < v[0]) {
if (flag && cnt == v[0] - 2) cout << "11";
if (cnt < v[it]) cout << 3;
else { --it, --cnt; cout << 7; }
cnt++;
}
cout << "7\n";
}
}

 

E. You Are Given Some Strings...

题意:先给出一个字符串\(t\)(全是字符串...),再给出\(n\)个字符串\(s1, s2, ..., s_n\)。定义函数\(f(t, s)\)为求出字符串\(s\)在\(t\)中的出现次数,例如:\(f(aaabacaa, aa)=3\)。现在要求出\(\sum_{i=1}^{n}\sum_{j=1}^{n}f(t, s_i+s_j)\)的值。

分析:我们考虑如果\(t\)串中存在\(s_i+s_j\)那么必然存在一个位置\(pos\)满足\(pos\)前面为后缀串\(s_i\),\(pos\)后面为前缀串\(s_j\),因此我们只需要对每一个\(pos\)跑出前缀串和后缀串的数量,乘法原理累加即可。而前缀串后缀串计数的操作只需要正反跑两次AC自动机即可。

AC代码

#include <bits/stdc++.h>
#define SIZE 200010
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
struct ACAM {
int cnt, trie[SIZE][26], fail[SIZE], q[SIZE], sum[SIZE], h, r, num[SIZE];
void insert(char s[], int n) {
int now = 0;
rep(i, 1, n) {
int p = s[i] - 'a';
if (!trie[now][p]) trie[now][p] = ++cnt;
now = trie[now][p];
}
sum[now]++;
}
void build() {
h = 1; r = 0;
rep(i, 0, 25) if (trie[0][i]) q[++r] = trie[0][i];
while (h <= r) {
int u = q[h++];
rep(i, 0, 25) {
if (trie[u][i]) {
fail[trie[u][i]] = trie[fail[u]][i];
sum[trie[u][i]] += sum[fail[trie[u][i]]];
q[++r] = trie[u][i];
}
else trie[u][i] = trie[fail[u]][i];
}
}
}
void solve(char s[], int n) {
int now = 0;
rep(i, 1, n) {
int p = s[i] - 'a';
now = trie[now][p];
num[i] = sum[now];
}
}
}AC[2];
int n, len;
char s[SIZE], t[SIZE], rs[SIZE], rt[SIZE];
int main() {
io(); cin >> (t + 1) >> n;
rep(i, 1, n) {
cin >> (s + 1);
len = strlen(s + 1);
for (int i = len; i; --i) rs[len - i + 1] = s[i];
AC[0].insert(s, len);
AC[1].insert(rs, len);
}
len = strlen(t + 1);
for (int i = len; i; --i) rt[len - i + 1] = t[i];
AC[0].build(); AC[1].build();
AC[0].solve(t, len); AC[1].solve(rt, len);
ll ans = 0;
rep(i, 1, len) ans += 1ll * AC[0].num[i] * AC[1].num[len - i];
cout << ans;
}

 

F. You Are Given Some Letters...

题意:给出两个正整数\(a\)代表\(A\)字符的数量,\(b\)代表\(B\)字符的数量,构造一个字符串(Stringforces...),使得字符串由某一循环节或循环节中的部分构成的,询问最多能找出几组能完成上述构造的不同循环节(仅长度不同的循环节被视作不同的)。

分析:我们首先把问题转化为数学形式。先设一个循环节的长度为\(k\),那么该循环节完整出现的次数\(n\)的表达式即为\(n=\lfloor \frac{a+b}{k} \rfloor\)。

同时,我们假设该循环节中\(A\)出现的次数为\(num_a\),\(B\)为\(num_b\),显然有\(num_a+num_b=k\)。并且我们可以得到下列不等式组:$$0 \leq a-n \cdot num_a \leq num_a$$ $$0 \leq b-n \cdot num_b \leq num_b$$

转化后得到:$$\lceil \frac{a}{n+1} \rceil \leq num_a \leq \lfloor \frac{a}{n} \rfloor$$ $$\lceil \frac{b}{n+1} \rceil \leq num_a \leq \lfloor\frac{b}{n} \rfloor$$

于是,我们得到了\(num_a\)和\(num_b\)的范围,当且仅当\(num_a\)和\(num_b\)均存在时,我们才可以满足条件的循环节。因此,我们不妨枚举循环节出现次数\(n\)的值,通过求得的\(num_a\)和\(num_b\)的存在范围来求解。

显然每次枚举,我们都应该将答案加上\(num_{amax}+num_{bmax}-num_{amin}-num_{bmin}+1\),即\(\lceil \frac{a}{n+1} \rceil + \lceil \frac{b}{n+1} \rceil - \lfloor \frac{a}{n} \rfloor - \lfloor \frac{b}{n} \rfloor + 1\),但要注意我们枚举了\(n\)的值,因此\(k\)是有范围的,\(\frac{a+b}{n+1} \leq k < \frac{a+b}{n}\)。时间复杂度\(o(\sqrt{n})\)。

AC代码

#include <bits/stdc++.h>
#define SIZE 200007
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
typedef long long ll;
void io() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
ll a, b;
string s;
int main() {
io(); cin >> a >> b;
ll ans = 0;
for (ll i = 1; i <= a + b;) {
ll n = (a + b) / i;
ll maxr = (a + b) / n;
if (n > a || n > b) { i = (a + b) / n + 1; continue; }
ll l = ceil(1.0*a / (n + 1)), r = a / n;
ll L = ceil(1.0*b / (n + 1)), R = b / n;
if (l <= r && L <= R) ans += max(0ll, min(maxr, r + R) - max(i, l + L) + 1);
i = maxr + 1;
}
cout << ans;
}

Educational Codeforces Round 70 (Rated for Div. 2) 题解的更多相关文章

  1. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

  2. Educational Codeforces Round 65 (Rated for Div. 2)题解

    Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...

  3. Educational Codeforces Round 64 (Rated for Div. 2)题解

    Educational Codeforces Round 64 (Rated for Div. 2)题解 题目链接 A. Inscribed Figures 水题,但是坑了很多人.需要注意以下就是正方 ...

  4. Educational Codeforces Round 60 (Rated for Div. 2) 题解

    Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...

  5. Educational Codeforces Round 58 (Rated for Div. 2) 题解

    Educational Codeforces Round 58 (Rated for Div. 2)  题目总链接:https://codeforces.com/contest/1101 A. Min ...

  6. Educational Codeforces Round 70 (Rated for Div. 2)

    这次真的好难...... 我这个绿名蒟蒻真的要崩溃了555... 我第二题就不会写...... 暴力搜索MLE得飞起. 好像用到最短路?然而我并没有学过,看来这个知识点又要学. 后面的题目赛中都没看, ...

  7. n=C(2,n)+k(构造)( Print a 1337-string)Educational Codeforces Round 70 (Rated for Div. 2)

    题目链接:https://codeforc.es/contest/1202/problem/D 题意: 给你一个数 n ( <=1e9 ),让你构造137713713.....(只含有1,3,7 ...

  8. (模拟)关于进制的瞎搞---You Are Given a Decimal String...(Educational Codeforces Round 70 (Rated for Div. 2))

    题目链接:https://codeforc.es/contest/1202/problem/B 题意: 给你一串数,问你插入最少多少数可以使x-y型机器(每次+x或+y的机器,机器每次只取最低位--% ...

  9. Educational Codeforces Round 47 (Rated for Div. 2) 题解

    题目链接:http://codeforces.com/contest/1009 A. Game Shopping 题目: 题意:有n件物品,你又m个钱包,每件物品的价格为ai,每个钱包里的前为bi.你 ...

随机推荐

  1. Centos 修改yum源为aliyun

    修改服务器源,避免长途跋涉到国外: 位置: vim  /etc/yum.repos.d/CentOS-Base.repo aliyun地址: 设置aliyun的yum源 wget -O /etc/yu ...

  2. 白面系列 kafka

    kafka是一个分布式发布订阅消息系统,也可叫做MQ系统,MQ是Message Queue,消息队列. 通俗点,生产者往队列里写消息,消费者从队列里读.专业点,Producer通过TCP协议发送消息到 ...

  3. vue自定义日期选择,类似美团日期选择,日历控件,vue日历区间选择

    一个日历的控件,基于vue的,可以日历区间选择,可用于酒店日历区间筛选,动手能力强,可以修改成小程序版本的,先上效果图 里面的颜色样式都是可以修改的 选择范围效果 话不多说,直接上干货,代码可以直接复 ...

  4. php设计模式之适配器模式实例代码

    <?php header("Content-type:text/html;charset=utf-8"); // 适配器模式 /** * 查看天气接口 */ class Ti ...

  5. Art Union

    A well-known art union called "Kalevich is Alive!" manufactures objects d'art (pictures). ...

  6. SpringScan

    ClassPathBeanDefinitionScanner.java /** * Perform a scan within the specified base packages, * retur ...

  7. Pyarm的Pyqt的配置

    相关连接: Python PyQt 安装python3.4 x64到c盘根目录. 安装PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x64.exe 安装pycharm-professio ...

  8. c数据结构 -- 链表的理解

    链表是结构体变量与结构体变量链接在一起,怎么链接在一起?通过指针 #include <stdio.h> struct Node{ int data; struct Node* next; ...

  9. vs2019 scanf 解决 C4996问题

    1. 首先选择项目 2. 然后选择最下面那行的 工程属性, 其后于此处 3. 添加上 :_CRT_SECURE_NO_WARNINGS 最后保存,使用 scanf 读取即无报错了

  10. python之路之网络基础

    c类地址