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

A. Permutaciones gemelas

A. Permutaciones gemelas

1. Análisis

El método de construcción del autor aquí es hacer que la matriz final satisfaga: 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=...=ayo+byo=norte+1

Ahora vamos a probar la corrección de este método de construcción.

Como nuestra suma es determinista, bi = n + 1 − ai b_i=n+1-a_ibyo=norte+1ayo
Gracias a nuestro ai a_iayoes una permutación, entonces ai a_iayoson diferentes por parejas, así que bi b_ibyoTambién es diferente. porque _El rango de a es[ 1 , n ] [1,n][ 1 ,n ] , así quebbEl rango de b es[ 1 , n ] [1,n][ 1 ,norte ] . mientrasbbLa longitud de la matriz b es nnnuevamentenorte _ Por lo tanto,bbLa matriz b es una secuencia de1 11 annLa longitud de la diferencia por pares de n es nnLa secuencia de n , es decir bbLa matriz b es una permutación. Se ajusta al significado del título.

2. Código

#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. Fusión de matriz

B. Fusión de matriz

1. Análisis

Esta pregunta tiene una propiedad muy importante, es decir, solo se toma uno de los primeros elementos de las dos matrices a la vez. Si no existe tal propiedad, simplemente cuente la suma del número de ocurrencias de diferentes números en las dos matrices y genere el valor máximo. Entonces, ¿qué impacto tiene la existencia de esta propiedad en la respuesta?

Aquí se prueban dos cosas:

Lo primero: se pueden empalmar dos números idénticos consecutivos cualesquiera . Supongamos que queremos juntar A y B, solo necesitamos sacar los números delante de A y B, empalmarlos delante y luego sacar A y B.
inserte la descripción de la imagen aquí

Lo segundo: No se pueden empalmar tres o más números idénticos consecutivos .
inserte la descripción de la imagen aquí
Como se muestra en la figura anterior, supongamos que queremos unir los tres segmentos de ABC, cuando conectamos A y B, debemos conectar el número entre Q y P, es decir, el continuo formado por nuestro A y B Los números deben interrumpirse, por lo que C no se puede conectar a A+B.

A través de las dos pruebas anteriores, podemos llegar a la siguiente conclusión:
Para cualquier número, encuentra el número de los números idénticos consecutivos más largos en las dos matrices y luego súmalos.
De esta forma, para cualquier número, se puede obtener un número sumado. Luego tome un valor máximo de estos números.

2. Código

#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. Árbol Niño dibuja árboles

C. Árbol Niño dibuja árboles

1. Análisis

Para el problema del árbol, primero podemos considerar el caso de una cadena.
inserte la descripción de la imagen aquí

Los números marcados en un borde son el orden en que se ingresó el borde. De acuerdo con el significado de la pregunta, la imagen de la izquierda se puede colorear de arriba a abajo, es decir, solo se requiere una operación. La imagen de la derecha es un caso extremo y la imagen de la derecha requiere 4 operaciones.

Entonces, ¿cuál es la regla?

Podemos encontrar la siguiente regla:
inserte la descripción de la imagen aquí
si x < y x < yX<Puedo colorear dos puntos en una sola operación. six > y x > yX>y , en una operación, no se pueden operar dos puntos al mismo tiempo. dondex > y x > yX>y puede considerarse como un par de orden inverso.

Para una cadena, el número de operaciones es igual al número de pares inversos en la cadena + 1.

A continuación consideramos el caso de un árbol.

Un árbol puede verse como muchas cadenas.
inserte la descripción de la imagen aquí

Durante la primera operación, los puntos azules del gráfico se colorearán correctamente. En la segunda pasada, los puntos blancos se colorean con éxito. Entonces la respuesta final es 2. Consideramos este árbol como varias cadenas, y podemos obtener la siguiente situación.
inserte la descripción de la imagen aquí
Después de dividir la figura en 4 cadenas, podemos usar la conclusión de ahora para obtener el número de operaciones de cada cadena. Y encontramos que la respuesta de este árbol es el número máximo de estas operaciones en cadena.

Por lo tanto, solo necesitamos encontrar el número de operaciones de cada cadena en el proceso de DFS y luego tomar un resultado máximo.

2. Código

#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. El BOSS puede contar pares

D. El BOSS puede contar pares

1. Análisis

Pensemos primero en el método violento. El método más violento es enumerar todos los pares posibles y luego juzgar si el par satisface ai ∗ aj = bi + bj a_i*a_j=b_i+b_jayoaj=byo+bj. Este proceso se puede escribir como C n 2 = n ( n − 1 ) 2 C_n^2=\frac{n(n-1)}{2}Cnorte2=2norte ( norte - 1 ), es decir, la complejidad del tiempo es O ( n 2 ) O(n^2)O ( n2 ). Obviamente, este enfoque ha caducado.

A continuación, pensemos en cómo optimizar el algoritmo de fuerza bruta.

Encontramos que esta pregunta tiene una propiedad muy crítica: ai ≤ n a_i\leq nayon sumabi ⪇ n b_i\lneq nbyonorte _

Esto significa que nuestro bi + bj ⪇ 2 n b_i+b_j\lneq2nbyo+bj2 n,即ai ∗ aj ≤ 2 n a_i*a_j\leq2nayoaj2 norte _

min ( ai , aj ) ⪇ 2 n min(a_i,a_j)\lneq \sqrt{2n}min ( unyo,aj)2 norte

Entonces podemos enumerar min ( ai , aj ) min(a_i,a_j)min ( unyo,aj) . (Puede desear denotar este valor mínimocomo sss , elsss comoaj a_jaj)。

Luego vamos al par enumerador ( ai , bi ) (a_i,b_i)( unyo,byo) . Entonces podemos usar la fórmula:ai ∗ aj = bi + bj a_i*a_j=b_i+b_jayoaj=byo+bjCalcular bj b_jbj

bj = ai ∗ aj − bi = s ∗ ai − bi b_j=a_i*a_j-b_i=s*a_i-b_ibj=ayoajbyo=sayobyo

Entonces nuestro ( aj , bj ) (a_j,b_j)( unj,bj)( s , s ∗ ai − bi ) (s,s*a_i-b_i)( s ,sayobyo) , y el número de este par de números es la contribución del par de números a la respuesta.

Ahora tenemos dos problemas que resolver.

Ya que estamos enumerando min ( ai , aj ) min(a_i,a_j)min ( unyo,aj) , entonces necesitamos garantizarai ≥ s a_i\geq sayos -como.

Si esto no está garantizado, surgirán problemas duplicados.

Al mismo tiempo, para calcular la contribución, necesitamos abrir una matriz para registrar todos los ( s , bi ) (s,b_i)( s ,byo) número.

如果ai > s a_i>sayo>s se puede calcular de acuerdo con la derivación de ahora.

como ai = s a_i=sayo=s , aquí necesita deduplicar.

¿Por qué ir pesado?

Porque en este momento ai = s a_i=sayo=s , por lo que los dos pares que elegimos en este momento son:( s , bi ) (s,b_i)( s ,byo) y( s , bj ) (s,b_j)( s ,bj) . De acuerdo con la idea de ahora, nuestro( i , j ) (i,j)( yo ,j ) y( j , yo ) (j, yo)( j ,i ) será calculado. De hecho, estos dos cuentan como uno.

2. Código

#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();
}

Supongo que te gusta

Origin blog.csdn.net/weixin_72060925/article/details/130981994
Recomendado
Clasificación