Directorio de artículos
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+1−ayo
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
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.
Lo segundo: No se pueden empalmar tres o más números idénticos consecutivos .
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
1. Análisis
Para el problema del árbol, primero podemos considerar el caso de una cadena.
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:
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.
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.
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
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_jayo∗aj=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 nayo≤n sumabi ⪇ n b_i\lneq nbyo⪇norte _
Esto significa que nuestro bi + bj ⪇ 2 n b_i+b_j\lneq2nbyo+bj⪇2 n,即ai ∗ aj ≤ 2 n a_i*a_j\leq2nayo∗aj≤2 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_jayo∗aj=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=ayo∗aj−byo=s∗ayo−byo。
Entonces nuestro ( aj , bj ) (a_j,b_j)( unj,bj)即( s , s ∗ ai − bi ) (s,s*a_i-b_i)( s ,s∗ayo−byo) , 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 sayo≥s -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();
}