# [LGR-096] solution to the problem of I Div.2 of Luogu November race

## preface

It's troublesome to write four articles after thinking about it (in fact, it's too fierce to read the water blog).
Then it was integrated.

### General idea of the topic

Give you a sequence. You can select two adjacent numbers at a time and combine them by one.
The form of consolidation is the first plus or minus and the last one.
Then you have to maximize the last remaining number.

### thinking

It is found that the first number must be a positive contribution, and you can be satisfied in any way, whether positive or negative.
Then the first one plus the following absolute value is the answer.

### code

```#include<cstdio>
#define ll long long

using namespace std;

int n, x;
ll ans;

int Abs(int x) {
return x < 0 ? -x : x;
}

int main() {
scanf("%d", &n);
scanf("%d", &x); ans = x;
for (int i = 2; i <= n; i++) {
scanf("%d", &x);
ans += 1ll * Abs(x);
}
printf("%lld", ans);

return 0;
}
```

## T2: Lines

### General idea of the topic

Give you some lines to ensure that there are no overlapping lines or that three lines have the same intersection.
Then ask how many lines you have to choose at least so that all the line intersections are on the line you choose.

### thinking

Consider that parallel edges do not have intersections.
Then you think about it, because no straight line has the same intersection, we can take the intersection of different slopes as the straight line of these two slopes, and choose at least one.
The conversion is that you can not choose a straight line with a slope at most. (because any two lines with different slopes will have an intersection)

Then you can count the number of straight lines of each slope, and then choose the one with the largest number instead of the one.

## code

```#include<map>
#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

int n, ans, maxn;
int a, b, c;
map <pair<int, int>, int> q;

int gcd(int x, int y) {
if (!y) return x;
return gcd(y, x % y);
}

int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d %d %d", &a[i], &b[i], &c[i]);
if (!a[i]) b[i] = 1;
if (!b[i]) a[i] = 1;
if (a[i] && b[i]) {
int g = gcd(a[i], b[i]);
a[i] /= g; b[i] /= g;
}
q[make_pair(a[i], b[i])]++;
}

for (map <pair<int, int>, int> :: iterator it = q.begin(); it != q.end(); it++) {
ans += (*it).second;
maxn = max(maxn, (*it).second);
}

printf("%d", ans - maxn);

return 0;
}
```

## T3: ABC

### General idea of the topic

I'll give you a string consisting of only three characters ABC.
Then you can select an interval each time and replace the ABC of the interval with the character you specify.
Then ask how many operations you need at least to make each adjacent position character the same.

## thinking

You consider that for an interval, its adjacent original state and current state will not change.
What will change is the two segments of the interval.
It's not hard to think that the two ends can be illegal every time. Then, if there is only one illegal place, one endpoint is it and the other endpoint is the rightmost.
Then, as for how to change it, you can change it casually, as long as you are sure that each is different from the previous one, so you can ensure that both sides will change from the same to different.
Then it's all right.

## code

```#include<cstdio>

using namespace std;

struct node {
int l, r;
char c;
}q;
int n, m, l, r;
char s;

bool gets() {
l = -1; r = -1;
for (int i = 2; i <= n; i++) {
if (s[i] == s[i - 1]) {
if (l == -1) l = i;
else {
r = i - 1;
break;
}
}
}
if (l == -1) return 0;
if (r == -1) r = n;
return 1;
}

int main() {
scanf("%d", &n);
scanf("%s", s + 1);

while (1) {
if (!gets()) break;
m++;
q[m].l = l;
q[m].r = r;
q[m].c = 'B';
q[m].c = 'C';
q[m].c = 'A';
for (int i = l; i <= r; i++) {
s[i] = q[m].c[s[i] - 'A'];
}
}

printf("%d\n", m);
for (int i = 1; i <= m; i++) {
printf("%d %d ", q[i].l, q[i].r);
for (int j = 0; j <= 2; j++) putchar(q[i].c[j]);
printf("\n");
}

return 0;
}
```

## T4: Permutation

### General idea of the topic

Give you a tree, and then ask you to find an array with the largest dictionary order, so that the number generated by it according to the following requirements is the isomorphic tree of the given number.
Each time, find the last point in front that is greater than its number, and then connect the edges of the two subscripts. If not, it will not connect the edges.

### thinking

First, let's consider greed, assuming that the root has been determined (enumerated), what should we do.
Then go down recursively every time you find the smallest tree.

But in fact, this is problematic, because different numbers of the same size have different advantages and disadvantages.
Then we consider how to solve it and find that we can sort it by recording its son's ranking.

Specifically, we should start from the lowest point and merge it bit by bit.
Specifically, enumerate each seed tree, and then arrange them by size, and then sort them of the same size each time, and then number them (note that the numbers of the same forms are the same), and then only the sorting will use this number.

Then it is not difficult to see that the first two must be \ (1\ n \), and then start from the smallest numbered subtree in the size \ (n-1 \).
Then recurse down and do it according to the son's priority.

Then pay attention to the special judgment that the size is \ (1 \).

### code

```#include<cstdio>
#include<vector>
#include<algorithm>

using namespace std;

struct node {
int fr, to, nxt;
}e;
int n, x, y, le, KK;
int sz, fa, pm;
int f, pl;
struct nde {
int id, sz;
vector <int> p;
}a;

void add(int x, int y) {
e[++KK] = (node){x, y, le[x]}; le[x] = KK;
e[++KK] = (node){y, x, le[y]}; le[y] = KK;
}

void dfs(int now, int father) {
sz[now] = 1; fa[now] = father;
for (int i = le[now]; i; i = e[i].nxt)
if (e[i].to != father) {
dfs(e[i].to, now);
sz[now] += sz[e[i].to];
}
}

bool cmp0(nde x, nde y) {
return x.sz < y.sz;
}

bool cmp1(int x, int y) {
return f[x] < f[y];
}

bool cmp2(nde x, nde y) {
int d = min(x.p.size(), y.p.size());
for (int i = 0; i < d; i++)
if (f[x.p[i]] != f[y.p[i]]) return f[x.p[i]] < f[y.p[i]];
return 0;
}

void write(int now, int k) {
for (int i = 0; i < a[now].p.size(); i++) {
printf(" %d", k - a[pl[a[now].p[i]]].sz + 1);
write(pl[a[now].p[i]], k);
k -= a[pl[a[now].p[i]]].sz;
}
}

int main() {
scanf("%d", &n);

if (n == 1) {//Special judgment
printf("1"); return 0;
}

for (int i = 1; i < n; i++) {
scanf("%d %d", &x, &y);
}

dfs(1, 0);

for (int i = 1; i <= KK; i++) {
int fr = e[i].fr, to = e[i].to;
if (fa[fr] == to) a[i].sz = n - sz[fr];
else a[i].sz = sz[to];
a[i].id = i;
for (int j = le[to]; j; j = e[j].nxt)
if (e[j].to != fr) {
a[i].p.push_back(j);
}
}
sort(a + 1, a + KK + 1, cmp0);//Arrange by size first
int l = 1, r = 0;
for (int S = 2; S < n; S++) {
while (l <= KK && a[l].sz < S) l++;//Found the same size
while (r < KK && a[r + 1].sz <= S) r++;
for (int i = l; i <= r; i++) sort(a[i].p.begin(), a[i].p.end(), cmp1);//Line up your sons first
sort(a + l, a + r + 1, cmp2);//Ranked by son
f[a[l].id] = ++pm;
if (S != n - 1) {
for (int i = l + 1; i <= r; i++) {
pm += cmp2(a[i - 1], a[i]);//Note that exactly the same is not added
f[a[i].id] = pm;
}
}
}

for (int i = 1; i <= KK; i++)
pl[a[i].id] = i;
printf("1 %d", n);
write(l, n - 1);

return 0;
}
```

Tags: Graph Theory dp

Posted on Sun, 31 Oct 2021 07:00:31 -0400 by kdreg