Codeforces Round 875 (Div. 2)(A—D)

A. Twin Permutations

A. Twin Permutations

1. Analysis

The author's construction method here is to make the final array satisfy: a 1 + b 1 = a 2 + b 2 = . . . = ai + bi = n + 1 a_1+b_1=a_2+b_2=...=a_i+b_i =n+1a1+b1=a2+b2=...=ai+bi=n+1

Now let's prove the correctness of this construction method.

Since our sum is deterministic, bi = n + 1 − ai b_i=n+1-a_ibi=n+1ai
Thanks to our ai a_iaiis a permutation, so ai a_iaiare pairwise different, so bi b_ibiIt is also different. because aaThe range of a is[ 1 , n ] [1,n][1,n ] , sobbThe range of b is[ 1 , n ] [1,n][1,n ] . whilebbThe length of the b array is nnagainn . Therefore,bbThe b array is a sequence from1 11 tonnThe length of the pairwise difference of n is nnThe sequence of n , ie bbThe b array is a permutation. It fits the meaning of the title.

2. Code

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

void solve()
{
    
    
	int n;
	cin >> n;
	vector<int>a(n);
	for(auto &x : a)
		cin >> x;
		
	for(int i = 0; i < n; i ++)
	{
    
    
		cout << n - a[i] + 1 << " ";
	}
	cout << endl;
}

signed main()
{
    
    
	ios::sync_with_stdio(0);
	cin.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

B. Array merging

B. Array merging

1. Analysis

This question has a very important property, that is, only one of the first elements of the two arrays is taken at a time. If there is no such property, just count the sum of the number of occurrences of different numbers in the two arrays, and output the maximum value. So what impact does the existence of this property have on the answer?

Two things are proven here:

The first thing: any two consecutive identical numbers can be spliced ​​together.
insert image description hereSuppose we want to put A and B together, we only need to take out the numbers in front of A and B, splice them in front, and then take A and B.

The second thing: Any three or more consecutive identical numbers cannot be spliced ​​together.
insert image description here
As shown in the figure above, suppose we want to connect the three segments of ABC together. When we connect A and B together, we must connect the number between Q and P, that is to say, the continuum formed by our A and B The numbers must be interrupted, so C cannot be connected to A+B.

Through the above two proofs, we can get the following conclusion:
For any number, find the number of the longest consecutive identical numbers in the two arrays, and then add them.
In this way, for any number, an added number can be obtained. Then take a maximum value from these numbers.

2. Code

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

void solve()
{
    
    
	int n;
	cin >> n;
	vector<int>a(n), b(n);
	for(int i = 0; i < n; i ++)
		cin >> a[i];
	for(int i = 0; i < n; i ++)
		cin >> b[i];
	
	map<int,int>ca, cb;
	for(int i = 0; i < n; i ++)
	{
    
    
		int cnt = 1;
		while(i + 1 < n && a[i] == a[i + 1])
			cnt ++, i ++;
		ca[a[i]] = max(ca[a[i]], cnt);
	}
	for(int i = 0; i < n; i ++)
	{
    
    
		int cnt = 1;
		while(i + 1 < n && b[i] == b[i + 1])
			cnt ++, i ++;
		cb[b[i]] = max(cb[b[i]], cnt);
	}
	map<int,int>ans;

	for(auto x : ca)
		ans[x.first] += x.second;	

	for(auto x : cb)
		ans[x.first] += x.second;

	int ANS = 0;
	for(auto x : ans)
		ANS = max(x.second, ANS);
	cout << ANS << endl;
}

signed main()
{
    
    
	ios::sync_with_stdio(0);
	cin.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

C. Tree Child Draws Trees

C. Tree Child Draws Trees

1. Analysis

For the tree problem, we can first consider the case of a chain.
insert image description here

The numbers marked on an edge are the order in which the edge was entered. According to the meaning of the question, the left picture can be colored from top to bottom in turn, that is, only one operation is required. The picture on the right is an extreme case, and the picture on the right requires 4 operations.

So what's the rule?

We can find the following rule:
insert image description here
if x < y x < yx<y can color two points in one operation. ifx > y x > yx>y , in one operation, two points cannot be operated at the same time. wherex > y x > yx>y can be regarded as a reverse order pair.

For a chain, the number of operations is equal to the number of inverse pairs on the chain + 1.

Next we consider the case of a tree.

A tree can be seen as many chains.
insert image description here

During the first operation, the blue points in the graph will be successfully colored. In the second pass, the white points are successfully colored. Then the final answer is 2. We regard this tree as various chains, and we can get the following situation.
insert image description here
After splitting into 4 chains in the figure, we can use the conclusion just now to get the number of operations of each chain. And we found that the answer of this tree is the maximum number of these chain operations.

Therefore, we only need to find the number of operations of each chain in the process of DFS, and then take a maximum output.

2. Code

#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii;
const int N = 2e5 + 10;
int e[N], f[N];
vector<pii>edge[N];
int ans = 0;

void dfs(int u, int father)
{
    
    
	for(auto [a, b]: edge[u])
	{
    
    
		if(a == father)
			continue;
		e[a] = b;
		f[a] = f[u] + (b < e[u]);
		dfs(a, u);
	}	
}

void solve()
{
    
    
	int n;
	cin >> n;
	for(int i = 0; i < n - 1; i ++)
	{
    
    
		int a, b;
		cin >> a >> b;
		edge[a].push_back({
    
    b, i});
		edge[b].push_back({
    
    a, i});
	}
	dfs(1, -1);
	int maxv = 0;
	for(int i = 0; i <= n; i ++)
	{
    
    
		maxv = max(f[i], maxv);
	}
	cout << maxv + 1 << endl;

	for(int i = 0; i <= n; i ++)
		edge[i].clear();
	for(int i = 0; i <= n; i ++)
		e[i] = f[i] = 0;
}

signed main()
{
    
    
	ios::sync_with_stdio(0);
	cin.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

D. The BOSS Can Count Pairs

D. The BOSS Can Count Pairs

1. Analysis

Let's think about the violent method first. The most violent method is to enumerate all possible pairs, and then judge whether the pair satisfies ai ∗ aj = bi + bj a_i*a_j=b_i+b_jaiaj=bi+bj. This process can be written as C n 2 = n ( n − 1 ) 2 C_n^2=\frac{n(n-1)}{2}Cn2=2n(n1), that is, the time complexity is O ( n 2 ) O(n^2)O ( n2 ). Obviously this approach has timed out.

Next, let's think about how to optimize the brute force algorithm.

We found that this question has a very critical property: ai ≤ n a_i\leq nain sumbi ⪇ n b_i\lneq nbin

This means that our bi + bj ⪇ 2 n b_i+b_j\lneq2nbi+bj2n,即 a i ∗ a j ≤ 2 n a_i*a_j\leq2n aiaj2 n

m i n ( a i , a j ) ⪇ 2 n min(a_i,a_j)\lneq \sqrt{2n} min(ai,aj)2 n

Then we can enumerate min ( ai , aj ) min(a_i,a_j)min(ai,aj) . (May wish to denote this minimum valueas sss , thesss asaj a_jaj)。

Then we go to the enumerator pair ( ai , bi ) (a_i,b_i)(ai,bi) . Then we can use the formula:ai ∗ aj = bi + bj a_i*a_j=b_i+b_jaiaj=bi+bjCalculate bj b_jbj

b j = a i ∗ a j − b i = s ∗ a i − b i b_j=a_i*a_j-b_i=s*a_i-b_i bj=aiajbi=saibi

Then our ( aj , bj ) (a_j,b_j)(aj,bj) ( s , s ∗ a i − b i ) (s,s*a_i-b_i) (s,saibi) , and the number of this number pair is the contribution of the number pair to the answer.

Now we have two problems to solve.

Since we are enumerating min ( ai , aj ) min(a_i,a_j)min(ai,aj) , so we need to guaranteeai ≥ s a_i\geq sais -like.

If this is not guaranteed, duplicate problems will arise.

At the same time, in order to calculate the contribution, we need to open an array to record all ( s , bi ) (s,b_i)(s,bi) number.

如果 a i > s a_i>s ai>s can be calculated according to the derivation just now.

such as ai = s a_i=sai=s , here you need to deduplicate.

Why go heavy?

Because at this time ai = s a_i=sai=s , so the two pairs we choose at this time are:( s , bi ) (s,b_i)(s,bi) and( s , bj ) (s,b_j)(s,bj) . According to the idea just now, our( i , j ) (i,j)(i,j ) and( j , i ) (j,i)(j,i ) will be calculated. In fact, these two count as one.

2. Code

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define a first
#define b second
using namespace std;
const int N = 1e5 + 10;

void solve()
{
    
    
	int n, ans = 0;
	cin >> n;
	vector<pair<int,int>>c(n);
	for(int i = 0; i < n; i ++)
		cin >> c[i].a;
	for(int i = 0; i < n; i ++)
		cin >> c[i].b;
	vector<int>cnt(n + 1);
	for(int s = 1; s * s <= 2 * n; s ++)
	{
    
    
		cnt.assign(n + 1, 0);
		for(int i = 0; i < n; i ++)
			if(c[i].a == s)
				cnt[c[i].b] ++;
		int cc = 0;
		for(int i = 0; i < n; i ++)
		{
    
    
			if(c[i].a < s)
				continue;
			int x = s * c[i].a - c[i].b;
			if(x < 1 || x > n)
				continue;
			if(c[i].a == s)
				cc += (cnt[x] - (c[i].b == x));
			else
				ans += cnt[x];
		}
		ans += (cc / 2);
	}
	cout << ans << endl;
}

signed main()
{
    
    
	ios::sync_with_stdio(0);
	cin.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

Guess you like

Origin blog.csdn.net/weixin_72060925/article/details/130981994