Comentário Seletiva 2017 – Seleção

por

Comentário por Murilo Maeda

Link do problema

Nesse problema há duas dificuldades principais: o tamanho grande da matriz, então não podemos nem percorrê-la nem mantê-la em uma matriz, e a forma desorganizada que os números aparecem na matriz, não há um padrão que nos permita concluir coisas sobre a posição e organização de números na matriz.

Para resolver o primeiro problema, basta simplesmente não mantermos a matriz. Vamos manter somente os vetores x e y e quando precisarmos de um valor, só somamos os valores necessários de x e y.

Agora, vamos resolver o segundo problema.

Note que, como queremos encontrar os K menores números, a posição deles na matriz não importa. Por isso, podemos ordenar os vetores x e y, do menor para o maior e formar a matriz M na qual M_{ij} = x[i] + y[j] . Agora, temos duas propriedades dessa matriz: em uma mesma linha, se a percorrermos de 1 a N, os valores estarão dispostos em ordem não decrescente. O mesmo ocorre quando percorremos uma coluna de 1 a N.

A partir disso, vamos analizar o que acontece quando queremos saber quantos valores menores ou iguais a um determinado valor c estão na matriz M. Note que, se encontrarmos em uma determinada linha l o índice k de modo que o valor M_{lk} é o maior valor maior ou igual a c na linha l, nas linhas com índice menor que l, o maior valor maior ou igual a c vai estar em um índice maior ou igual a k, já que os valores em uma coluna e em uma linha estão em ordem não decrescente. Por isso, para um determinado número c, para descobrir quantos valores menores ou iguais a ele estão na matriz M, podemos simplesmente fazer o seguinte: passamos pela linha n e pegamos k_n e o somamos no número de valores menores ou iguais a c. Para uma linha l: a percorremos a partir do índice k_{l+1} enquanto os valores forem menores ou iguais a c. Paramos no índice k_{l} e somamos k_l no número de valores menores ou iguais a c.

Com isso, podemos calcular em O(n) quantos valores são menores ou iguais a c na matrisz M. Então, basta fazermos uma busca binária na resposta, tentando encontrar o valor que queremos. Fazemos isso chutando o número da resposta, checando quantos valores são menores ou iguais a ele em M e em seguida comparando esse resultado com k.

Segue o código para maior esclarecimento:


#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1e6 + 10;
int x[MAXN],y[MAXN];
int n,k, maior;
//Calculo para um valor val quantos números menores ou iguais a ele estão na matriz
bool calc(int val)
{
int aux = 0;
int j = 0;
//Passo por cada linha
for(int i = n; i > 0; i–)
{
//Tento aumentar o j. Note que o j não é zerado quando mudo de linha
while(x[i] + y[j + 1] <= val && j < n)
{
j++;
}
//Adiciono J no número de valores menores ou iguais a val na matriz
aux += j;
}
//Comparo com k para a busca binária
if(aux >= k) return true;
return false;
}
//Busca binária na resposta
int bsearch()
{
int ini = x[1] + y[1];
int fim = maior;
while(ini < fim)
{
int m = (ini + fim)/2;
//Testo se a nossa resposta for m
if(calc(m))
fim = m;
else
ini = m + 1;
}
return fim;
}
int32_t main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> n >> k;
int ax,bx,cx,mx; cin >> ax >> bx >> cx >> mx;
int ay,by,cy,my; cin >> ay >> by >> cy >> my;
x[1] = ax;
y[1] = ay;
for(int i = 2; i <= n; i++)
{
x[i] = (bx + cx*x[i-1])%mx;
y[i] = (by + cy*y[i-1])%my;
}
//Ordeno os vetores para organizar a matriz
sort(x + 1, x + (n + 1));
sort(y + 1, y + (n + 1));
maior = x[n] + y[n];
cout << bsearch();
}

view raw

selecao.cpp

hosted with ❤ by GitHub