# CTU Open Contest 2019 supplement

Posted by cmanhatton on Mon, 24 Feb 2020 06:36:38 +0100

The title of this competition is A B F C G J H E I D in ascending order according to the number of people passing.
Official data, questions and Solutions

### Article directory

#### A. Beer Barrels

Brief introduction
Give four integers: A, B, K, C, A,B,C are all single digits greater than 0. Ask how many of the K digits consist of only a or B (each of the K digits is a or B) are the numbers of C.

Solving problems
First of all, consider the simple situation. For C! = A & & C! = B, the answer is 0; for C = A = B, the answer is K. Otherwise, for any k-digit, because each of them has two choices, a total of 2K 2 ^ k2k choices, in general, there are 2k2^k2k different k-digits.

Among these 2k2^k2k numbers, there are 2K − 12^{k-1}2k − 1 for the first digit equal to C, and 2K − 12^{k-1}2k − 1 for the second digit equal to C, similarly, the third and fourth digit The final answer is k * 2K − 1K * 2 ^ {k-1} k * 2K − 1.

Code example

```#include<bits/stdc++.h>
using namespace std;
const int P = 1e9+7;
typedef long long ll;
ll a,b,c,k;
ll qpow(ll a,ll b,ll p){
ll res = 1;
if(b < 0) return 0; //Special judgment when k = 0
while(b){
if(b&1) res = res*a%p;
a = a*a%p;
b >>= 1;
}
return res;
}
int main(){
scanf("%lld%lld%lld%lld",&a,&b,&k,&c);
if(c != a && c != b){puts("0"); return 0;}
else if(a == b && a == c){printf("%d\n",k); return 0;}
printf("%lld\n",k*qpow(2,k-1,P)%P);
return 0;
}
```

#### B. Beer Bill

Brief introduction
Calculates the price of the string. For multiple strings, each string takes one line. There are two kinds of strings. One is called Raked Line, which contains only C '|' characters. The price of this string is defined as 42 * C. Another string is called PricedLine, which starts with the number price and uses two characters in the middle. "-" connect "and ends with consecutive C '|". , the price of this string is defined as price * C. if there is no '|' at the end, then C defaults to 1. Calculates the total price of all strings, rounded up to a multiple of 10.

Solving problems
This question is a reading comprehension question, after reading the meaning of the question, the code is very simple. You can encapsulate the price calculation code as a function calc(), and finally call it once for each price read in. Don't forget to round the answers up to ten.

Code example

```#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline bool isNum(char ch){
return ch >= '0' && ch <= '9';
}
int calc(const string& str){
if(isNum(str)){
int res = 0, i = 0;
for(;isNum(str[i]);i++) res = res*10+str[i]-'0';
int len = str.length()-i-2;
return len?len*res:res;
}else return 42*str.length();
}
int main(){
string str; ll ans = 0;
while(cin >> str) ans += calc(str);
if(ans%10) ans += 10-ans%10;
cout << ans << ",-" << endl;
return 0;
}
```

#### C. Beer Coasters

Brief introduction
Given the center (x, y) and radius r of a circle, the coordinates of two points of a rectangle are given, and the area of intersection between the rectangle and the circle is calculated.

Solving problems
Use the template of intersection area of circle and rectangle to find.

#### D. Beer Flood

Brief introduction
Given a directed graph without self ring and multiple edges, it is required to delete at most several redundant edges under the condition that "from the source point to any point, from any point to the join point". Among them, the source point is the point with zero degree in the graph, and the sink point is the point with zero degree in the graph.

Solving problems
Bipartite graph problem.

Code example

#### E. Beer Game

Brief introduction
Given two strings, the string contains only numbers and lowercase letters. You can do the following:

1. Insert: you can insert a character into a string.
2. Exchange: if a digit is x, then this x can be exchanged for any x lowercase letters (must be exchanged!)
3. Delete: you can select a position and delete the lowercase letters in that position.

Output the minimum number of operations to make the two strings equal.

Solving problems
Compared with the ordinary "edit distance" problem, the only difference is that if a number is encountered, it must be replaced with any lowercase letters, that is to say, several numbers need to be operated several times in the first place. We can preprocess first, so that the numbers are all replaced by the corresponding length of 'ා', which represents the wildcard, so that it can be converted into the "edit distance" problem.
It should be noted that if there are consecutive numbers, they are not regarded as the whole decimal system, but as individual numbers.

Let f [i, J] indicate "how many operations are required to match the first i characters of string a and the first j characters of string b at least". Pay attention to the space size!!!

Code example

```#include<bits/stdc++.h>
using namespace std;
string a,b;
string str1 = "#",str2 = "#";
int cnt = 0;	//Expand numbers several times
string epd(int x){
string s = ""; cnt++;
for(int i = 1;i <= x;i++) s += '#';
return s;
}
int f;
void solve(){
int n = str1.length()-1, m = str2.length()-1;
for(int i = 1;i <= n;i++) f[i] = i;
for(int i = 1;i <= m;i++) f[i] = i;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++){
f[i][j] = min(f[i][j-1],f[i-1][j])+1;
if(str1[i] == str2[j] || str1[i] == '#' || str2[j] == '#')
f[i][j] = f[i-1][j-1];
}
printf("%d\n",f[n][m]+cnt);
}
int main(){
cin >> a >> b;
//Preprocessing, expand all numbers
for(int i = 0;a[i];i++)
if(a[i] >= '0' && a[i] <= '9') str1 += epd(a[i]-'0');
else str1 += a[i];
for(int i = 0;b[i];i++)
if(b[i] >= '0' && b[i] <= '9') str2 += epd(b[i]-'0');
else str2 += b[i];
//Call solve function to solve
solve();
return 0;
}
```

#### F. Beer Marathon

Brief introduction
There are n points on the one-dimensional coordinate axis, and the value range is [- 1e6, 1e6]. Please move these n points to the adjacent two points every k, and what is the minimum total distance to move.

Solving problems
At the beginning, i want to use dynamic planning. Let f [i, 0] indicate that the ith point does not move, only move the minimum total distance of the first i points, f [i, 1] indicate the minimum total distance of the first i points, and then use POS [i, 1 | 0] to assist in recording the location; however, this is wrong, because when the total distance of movement is the same, i may have several different locations, but the above-mentioned method can only record one, and which one is the best one with aftereffect.

And then consider using the three-dimensional solution. The purpose of this paper is to find an optimal solution, that is to say, the total distance of moving is the smallest. It is easy to get that whether the starting point moves left or right, the result will change, and this change has a certain concave function property, that is, once it moves past a certain point, the total distance will change from decreasing to increasing, so it can be solved by the three-way method.

The next step is data range analysis. The final answer may be 1e12 * 1e6 = 1e18, so once the interval of three points is too large (for example, INF = 1e14), it will explode long. The feasible region is obviously [- 1e12, 1e12].

Code example

```#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n,k,a[N];
typedef long long ll;
const ll INF = 1e12;
ll Abs(ll x){return x>0?x:-x;}
ll check(ll m){//Count the shortest total distance when starting from m
ll res = 0;
for(int i = 1;i <= n;i++) res += Abs(a[i]-m),m += k;
return res;
}
void solve(){
ll l = -INF,r = INF;
while(l+1 < r){	//Start left or right
ll lm = l+r>>1, rm = lm+r>>1;
if(check(lm) < check(rm)) r = rm;
else l = lm;
}
printf("%lld\n",check(l));	//The final answer is in the l position
}
int main(){
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++) scanf("%d",a+i);
sort(a+1,a+1+n);	//Prioritize
solve();
return 0;
}
```

#### G. Beer Mugs

Brief introduction
Given a string s, select the longest substring, so that the characters of the substring can become a palindrome string by recombining (in any order), and output the length of the substring.

Solving problems
A string can be combined into a palindrome string. There are two possibilities: one is that the length is even, and all characters are required to be even; the other is that the length is odd, and only one character is odd, and others are even.
So what we need is only the parity of each character in a substring. Since a~t has 20 characters in total, we can store the prefix of s with 21 binary bits. A position of 0 indicates that there are even characters, and a position of 1 indicates that there are odd characters. Then we can transfer in O (1) time. Then a tag array is used to record the first occurrence position of each integer (binary decimal integer). For each x (current integer), as long as there is only one binary bit traversing with all prefixes different from it.

Code example

```#include<bits/stdc++.h>
using namespace std;
const int N = 1<<21;
int vis[N],n,ans = 0;
char str[N];
void solve(){
memset(vis,-1,sizeof vis); vis = 0;
for(int i = 1,x = 0;i <= n;i++){
x ^= (1<<(str[i]-'a'));
if(vis[x] != -1) ans = max(ans,i-vis[x]);
for(int j = 0,tmp;j < 21;j++){
tmp = x^(1<<j);
if(vis[tmp] != -1) ans = max(ans,i-vis[tmp]);
}
//cout << x << " " << vis[x] << endl;
if(vis[x] == -1) vis[x] = i;
}
printf("%d\n",ans);
}
int main(){
scanf("%d",&n); scanf("%s",str+1);
solve();
return 0;
}
```

#### H. Screamers in the Storm

Brief introduction
On a matrix of m * n, each square is composed of different elements, with the following rules:

1. Every turn, the wolf can only walk to the right, and if he can't walk, he can walk to the left. The sheep can only walk down. If they can't walk, they can walk up.
2. If the wolf and the sheep are in the same square, then the wolf eats the sheep, which is marked as "cemetery".
3. If the sheep are on the grass, the grid will become "bare" when they eat grass.
4. If the wolf doesn't eat the sheep within 10 rounds, it will die. Its dead square will become "graveyard". If the sheep doesn't eat the grass within 5 rounds, it will die. Its dead square will become "graveyard".

The conversion rules between different blocks are as follows:

1. 'bare' will become 'grass' after three rounds
2. "Grassland" will become "bare" when eaten by sheep
3. The cemetery can be passed by, but it will never grow grass.

Give the initial graph and output the state after T turn.

Solving problems
It should be a simulation problem, but the situation is more complicated. Each square may be in four states (grassland, graveyard, bare, several rounds since the last time it was eaten), while sheep and wolves have three states (what kind of creature is it, is it dead, where it is, when it was last eaten).

After more than ten hours, I always changed this and the wrong one. Some of them don't know how to express the meaning of the question. Some of the data are that the wolf goes first, the sheep goes after, and some of the wolves and the sheep go at the same time.

Code example

```#include <bits/stdc++.h>
using namespace std;
using ii = pair<int,int>;
#define F(i,a,b) for (int i = (int)(a); i < (int)(b); ++i)

const int GRASS_TIMER =  3;
const int SHEEP_TIMER =  5;
const int WOLF_TIMER  = 10;

void printState(const vector<string> & board, const vector<vector<int>> & grass, const vector<vector<int>> & hunger) {
int rows = board.size();
int cols = board.size();
F(r, 0, rows) {
F(c, 0, cols) {
if (board[r][c] != '.')
cout << board[r][c];
else if (grass[r][c] < 0)
cout << "*";
else if (grass[r][c] >= GRASS_TIMER)
cout << "#";
else
cout << ".";
}
cout << endl;
}
}

void makeMove(vector<string> & board, vector<vector<int>> & grass, vector<vector<int>> & hunger) {
int rows = board.size();
int cols = board.size();
vector<string> newBoard(rows, string(cols, '.'));
auto newGrass = grass;
vector<vector<int>> newHunger(rows, vector<int>(cols));
// move sheep
F(r, 0, rows) {
F(c, 0, cols) {
if (board[r][c] == 'S') {
newHunger[(r+1)%rows][c] = hunger[r][c];
newBoard [(r+1)%rows][c] = 'S';
}
}
}
// move wolves
F(r, 0, rows) {
F(c, 0, cols) {
if (board[r][c] == 'W') {
newHunger[r][(c+1)%cols] = hunger[r][c];
if (newBoard[r][(c+1)%cols] == 'S') {
// eat sheep
newGrass [r][(c+1)%cols] = -1e9;
newHunger[r][(c+1)%cols] = -1;
}
newBoard[r][(c+1)%cols] = 'W';
}
}
}
// eat grass
F(r, 0, rows) {
F(c, 0, cols) {
if (newBoard[r][c] == 'S' && newGrass[r][c] >= GRASS_TIMER) {
newHunger[r][c] = -1;
newGrass [r][c] = -1;
}
}
}
// grow hunger
F(r, 0, rows) {
F(c, 0, cols) {
if (newBoard[r][c] == 'S' || newBoard[r][c] == 'W')
++newHunger[r][c];
}
}
// die of hunger
F(r, 0, rows) {
F(c, 0, cols) {
if (newBoard[r][c] == 'S' && newHunger[r][c] >= SHEEP_TIMER) {
newGrass [r][c] = -1e9;
newHunger[r][c] = 0;
newBoard [r][c] = '.';
}
if (newBoard[r][c] == 'W' && newHunger[r][c] >= WOLF_TIMER) {
newGrass [r][c] = -1e9;
newHunger[r][c] = 0;
newBoard [r][c] = '.';
}
}
}
// grow grass
F(r, 0, rows) {
F(c, 0, cols) {
++newGrass[r][c];
}
}
swap(board, newBoard);
swap(grass, newGrass);
swap(hunger, newHunger);
}

int main() {
int turns, rows, cols;
cin >> turns >> rows >> cols;
vector<string> board(rows);
for (auto & row : board)
cin >> row;

vector<vector<int>> grass (rows, vector<int>(cols));
vector<vector<int>> hunger(rows, vector<int>(cols));
while (turns--) {
// printState(board, grass, hunger);
// cout << endl;
makeMove(board, grass, hunger);
}
printState(board, grass, hunger);
cout << endl;

return 0;
}
```

No look

#### J. Beer Vision

Brief introduction
Given a graph G1 composed of several points, all of which move according to a certain vector to get the graph G2, now the graph after G1 and G2 are mixed is given, please answer that the graph may be obtained by G1 moving along several different non-zero vectors.
Enter n points, each represented by (x, y).

Solving problems
If a vector is legal, any point moving forward or backward according to the vector must coincide with another point.
All vectors have at most n possibilities, that is, the vectors between any point and other points can be calculated, and then judged by dichotomy. The total time complexity is O (n 2) O (n2) O (n2) O (n2)

Code example

```#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+10;
int n,ans = 0;
pair<int,int> pa[N];
set<pair<int,int> > st;
bool check(int x,int y){
for(int i = 1;i <= n;i++){
bool flag = false;
pair<int,int> tmp = make_pair(pa[i].first-x,pa[i].second-y);
flag |= st.find(tmp) != st.end();
tmp = make_pair(pa[i].first+x,pa[i].second+y);
flag |= st.find(tmp) != st.end();
if(!flag) return false;
}
return true;
}
void solve(){
sort(pa+1,pa+1+n);
for(int i = 1;i <= n;i++) st.insert(pa[i]);
for(int i = 2;i <= n;i++){
int x = pa[i].first-pa.first;
int y = pa[i].second-pa.second;
if(check(x,y)) ans += 2;
}
printf("%d\n",ans);
}
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%d%d",&pa[i].first,&pa[i].second);
solve();
return 0;
}
```

#### summary

Before that, I always thought my English reading level was ok, at least higher than the average, but I was wrong. I read too hard in this competition.
There are 10 questions in total this time. I can finish 6 questions by myself. C is to find the intersection area of rectangle and circle in the plane. I am not familiar with the calculation geometry and have no idea. H is simulation. I have written for a long time but I can't get past several points. I haven't seen it.
Generally speaking, this set of questions is not very difficult, but many of them are easy to deviate from each other in understanding the meaning of the questions, leading to the failure of previous achievements. Moreover, if it is not for the test data, it is difficult for me to write correctly in a short time, so I still need to practice.  263 original articles published, 294 praised, 720000 visitors+