# 3 school Simulation Competition

Summary:

Make an expectation dp /se

Examination process:

After reading T1 and ahhhhhhhh in 5 min utes, sign in the question, and write it in 10 min utes. One too large example is sent.

8: 20 open dry T2, expect dp, after reading the questions, I feel I can do it.

I wrote it for a long time, adjusted the sample, wrote the opposite shot, and hung it as soon as I took it, rnm.

Adjust for half a day, transfer write hang ==

10: 10 open T3

T3 topic is so strange. Why is T2 topic at the beginning? It's useless. It's deleted.

Shit, where is the flower shop and my home? Why can't I find my home!! Children who can't find home

After reading it several times, I didn't understand the problem. I got numb and went to sleep.

After the game: Why did I miss a natural paragraph in T3!!!!

## T1 three-way city

Problem surface

solution

Touch the topic and you find that this is a full binary tree.

Then you will find that his layers are actually very few.

You will also find that the father of each node is to change node / 2

Then you jump up violently ==

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAX = 35;
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int q, Ans;
int get(int x) {
for (int i = 1; i <= MAX; i++)
if((1 << i) > x) return i;
}
signed main(){
//freopen("city.in", "r", stdin);
//freopen("city.out", "w", stdout);
for (int i = 1, x, y; i <= q; i++) {
Ans = 0;
int dep_x = get(x), dep_y = get(y);
if(dep_x < dep_y) swap(x, y), swap(dep_x, dep_y);
while(dep_x != dep_y) {
x = x / 2;
Ans++, dep_x--;
}
while(x != y) {
x = x / 2, y = y / 2;
Ans += 2;
}
cout<<Ans<<"\n";
}
return 0;
}



## T2 soul painter

Problem surface

solution

Expectation = probability * weight

Obviously, the weight is the color. Consider how to calculate the probability that each position becomes a color.

It is not difficult to find out which color a position becomes only related to the number of times it is selected.

Let \ (P {i, j} \) represent the probability that a point of \ (i \) appears in \ (i \) intervals and is selected \ (j \) times.

Obviously \ (P {I, J} = \ frac {C {I} ^ {J} {2} \)

Let \ (f_{i, j} \) represent the probability that \ (I \) is selected for times and becomes color \ (j \).

$$f_{i + 1, j \times o \% c} += f_{i, j} / c$$

$$P$$ and \ (f \) can be preprocessed.

$$Ans = \sum_{i = 1}^{i \leq n}\sum_{j = 0}^{cnt[i]}\sum_{o = 0}^{o < c} f_{j, o} \times P_{cnt[i], j} \times o$$

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 110;
const double eps = 1e-7;
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n, c, k, cnt[MAXN];
double C[MAXN][MAXN], P[MAXN][MAXN], Ans;
void Init_C() {
C[0][0] = 1;
for (int i = 1; i <= 100; i++) {
C[i][0] = 1;
C[i][0] = C[i][0] / 2.0;
for (int j = 0; j <= i; j++) {
C[i][j] = C[i - 1][j - 1] / 2.0 + C[i - 1][j] / 2.0;
}
}
}
void Init_P() {
P[0][1] = 1;
for (int i = 0; i <= k; i++)
for (int j = 0; j < c; j++) {
if(P[i][j] <= eps) continue;
for (int o = 0; o < c; o++) {
P[i + 1][j * o % c] = (P[i + 1][j * o % c] + P[i][j] / c);
}
}
}
int main(){
Init_C(), Init_P();
for (int i = 1; i <= k; i++) {
for (int j = x; j <= y; j++) cnt[j]++;
}
for (int i = 1; i <= n; i++)
for (int j = 0; j <= cnt[i]; j++)
for (int o = 0; o < c; o++) Ans += C[cnt[i]][j] * P[j][o] * o;
printf("%.3lf\n", Ans);
return 0;
}


## T3 Vanilla

Problem surface

solution

Move szt directly / cy

If you look at this data range, you can see that the shape voltage is required. If it requires the shortest path, it must have the shortest shape voltage.

Let's run a \ (Folyd \) to find the shortest distance between two pairs.

We are setting two arrays \ (f[S][i],g[S][i] \) to represent \ (1 \) as the starting point, the state of harvesting / sowing is \ (s \), the last point is the shortest distance of \ (I \), and the \ (g \) array represents \ (n \) as the starting point.

The above \ (f,g \) array can be preprocessed. The time complexity is \ (O(2^nn^2) \), which is a bit dangerous. We find that we don't need to enumerate all, we just need to enumerate the number of \ (1 \) in \ (S \) (≤ \ frac{n − 2}{2} + 2 \). The complexity is optimized by one \ (n \) (we still enumerate all subsets, but only do \ (O(n)\) Check on some subsets)

Then you enumerate which \ (n − 2 \) flower fields to harvest first, and set the status of the enumerated harvested flower fields to \ (S \).

We consider the harvesting process and how to combine the shortest path of the first half and the shortest path of the second half, that is, enumerate the points \ (i \) in the set and the points \ (j \) not in the set, and set the answer to \ (res \), then:

$$res=min\{f[S|1][i] + g[M \oplus (S|(1<<n−1))][j]+dis[i][j]\}$$
Where \ (M \) represents the complete set of all points.

This ensures that the selected points in the \ (S \) state will be harvested in the front \ (\ frac{n − 2} {2} \) flower field, and the remaining points will be harvested later.

Similarly, when we consider the process of sowing, in fact, it is the reverse. We set another sowing answer \ (ans \), then

$$ans=\min\{g[S|1][i]+f[M \oplus (S|(1<<n−1))][j]+dis[i][j]\}$$

The final answer is \ (min\{res+ans \} \).

Just search directly. Control the upper search limit and control the complexity to \ (O(2^{\frac{n − 2}} \ frac {n − 2} {2} ^ 2) \).

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 21;
const int INF = 0x3f3f3f3f3f;
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n, m, dis[MAXN][MAXN], N, M, Ans = 0x3f3f3f3f;
int f[MAXN][(1 << 20) - 1], g[MAXN][(1 << 20) - 1];
void Init_dis() {
for (int i = 1; i <= n; i++) dis[i][i] = 0;
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
void Init_F() {
memset(f, 0x3f, sizeof f);
f[1][1] = 0;
for (int s = 0; s < (1 << n); s++) {
int cnt = 0;
for (int k = 1; k <= n; k++) if(s & (1 << k - 1)) cnt++;
if (cnt > N + 2) continue;
for (int i = 1; i <= n; i++) {
if(!(s & (1 << i - 1))) continue;
for (int j = 1; j <= n; j++) {
if(s & (1 << j - 1)) continue;
f[j][s | (1 << j - 1)] = min(f[j][s | (1 << j - 1)], f[i][s] + dis[i][j]);
}
}
}
}
void Init_G() {
memset(g, 0x3f, sizeof g);
g[n][1 << n - 1] = 0;
for (int s = 0; s < (1 << n); s++) {
int cnt = 0;
for (int k = 1; k <= n; k++) if(s & (1 << k - 1)) cnt++;
if(cnt > N + 2) continue;
for (int i = 1; i <= n; i++) {
if(!(s & (1 << i - 1))) continue;
for (int j = 1; j <= n; j++) {
if(s & (1 << j - 1)) continue;
g[j][s | (1 << j - 1)] = min(g[j][s | (1 << j - 1)], g[i][s] + dis[i][j]);
}
}
}
}
int In[MAXN], Out[MAXN], Incnt, Outcnt;
void dfs(int s, int pos, int cnt) {
if(cnt > N) return ;
if(pos == n) {
if(cnt != N) return ;
int ret_1 = INF, ret_2 = INF;
for (int i = 1; i <= Incnt; i++) {
for (int j = 1; j <= Outcnt; j++) {
int x = In[i], y = Out[j];
ret_1 = min(ret_1, f[x][s | 1] + g[y][(s | 1) ^ M] + dis[x][y]);
ret_2 = min(ret_2, g[x][s | (1 << n - 1)] + f[y][(s | (1 << n - 1)) ^ M] + dis[x][y]);
}
}
Ans = min(Ans, ret_1 + ret_2);
return ;
}
In[++Incnt] = pos;
dfs(s | (1 << pos - 1), pos + 1, cnt + 1);
Incnt--;
Out[++Outcnt] = pos;
dfs(s, pos + 1, cnt);
Outcnt--;
}
int main(){
N = (n - 2) / 2, M = (1 << n) - 1;
memset(dis, 0x3f, sizeof dis);
for (int i = 1, u, v, w; i <= m; i++) {
dis[u][v] = dis[v][u] = min(dis[u][v], w);
}
Init_dis();
if(n == 3) {
cout<<(dis[1][2] + dis[2][3]) * 2;
return 0;
}
Init_F(), Init_G();
dfs(0, 2, 0);
cout<<Ans;
return 0;
}


Posted by Walle on Wed, 03 Nov 2021 16:48:40 -0700