Comentário por Lúcio Cardoso
Xadrez
Conhecimento prévio necessário:
Seja o quadrado na linha e coluna do tabuleiro. Já que a cor do quadrado é branca, a cor de cada quadrado pode ser encontrada baseando-se nos seguintes casos:
1. Se x e y tem a mesma paridade, a cor de é branca.
2. Se x e y tem paridades diferentes, a cor de é preta.
Como queremos encontrar a cor do (canto inferior direito), basta checar em qual dos casos o quadrado se encaixa, imprimindo sua respectiva cor. Segue o código para melhor entendimento.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Xadrez - Fase 1 P1 - 2018 | |
//Por Lucio Cardoso | |
//Complexidade: O(1) | |
#include <bits/stdc++.h> | |
using namespace std; | |
int main(void) | |
{ | |
int l, c; | |
cin >> l >> c; | |
if ((l%2) == (c%2)) { | |
// se l e c tem mesma paridade | |
cout << "1\n"; | |
} | |
else { | |
// se l e c tem paridades distintas | |
cout << "0\n"; | |
} | |
} |
Escadinha
Conhecimento prévio necessário:
Perceba que uma escadinha é, na verdade, uma Progressão Aritmética (PA). Então, o problema se resume em encontrar a quantidade de PAs na sequência tais que nenhuma delas esteja totalmente contida em alguma outra,
e todas as PAs calculadas possuam o maior tamanho possÃvel. Assim, para um Ãndice (inicialmente 1), encontraremos o maior Ãndice tal que a sequência de a seja uma PA, repetindo o processo novamente, ou seja, fazendo o novo indÃce inical de uma escadinha sendo , até que o último Ãndice seja o próprio fim da sequência . Segue o código para melhor entendimento.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Escadinha - Fase 1 P1 - 2018 | |
//Por Lucio Cardoso | |
//Complexidade: O(n) | |
#include <bits/stdc++.h> | |
using namespace std; | |
const int MAXN = 1010; | |
// sequência de números | |
int num[MAXN]; | |
int main(void) | |
{ | |
int n; | |
cin >> n; | |
for (int i = 1; i <= n; i++) | |
cin >> num[i]; | |
// faremos esse caso separadamente | |
if (n == 1) | |
{ | |
cout << "1\n"; | |
return 0; | |
} | |
// resposta do problema | |
int ans = 0; | |
for (int i = 1; i < n; i++) | |
{ | |
// razão da PA | |
int dif = num[i]-num[i+1]; | |
for (int j = i; j < n; j++) | |
{ | |
// se j é o último número na PA | |
if (num[j]-num[j+1] != dif) | |
{ | |
// na prox. iteração, i receberá j-1+1 = j | |
i = j-1; | |
break; | |
} | |
// n é o último número da PA, então faço i = n-1 para sair do loop | |
if (j+1 == n) i = n-1; | |
} | |
// chegamos ao fim da PA atual, então incremento ans | |
ans++; | |
} | |
cout << ans << "\n"; | |
return 0; | |
} |
Pirâmide
- Programação dinâmica (Aula 13)
Para cada linha da pirâmide com caixas numeradas por colunas de a , a linha acima possui caixas consecutivas, ou com colunas desde a , ou desde a , já que, caso contrário, ao menos uma das caixas não possuiria uma respectiva caixa abaixo dela, na linha . Assim, podemos utilizar uma função recursiva para encontrar a resposta mÃnima do problema, representando a pirâmide com a linha de Ãndice em sua base, e que por sua vez tem caixas consecutivas a partir da coluna . Temos, assim, que:
1. O caso base da função pode ser tomado quando , já que a resposta neste caso é apenas o valor da caixa na linha , coluna .
2. Como a linha é a base da pirâmide, a soma de todos os valores das caixas desde a coluna até a coluna estará incluÃda na resposta de .
3. Pelas observações anteriores, há dois casos para a coluna inicial na linha : ou , ou . Perceba que assim, a coluna final em tal linha está definida: será, respectivamente, ou , já que a linha possui caixas. Como queremos a soma mÃnima possÃvel dos valores das caixas, escolheremos o mÃnimo entre estes dois casos.
Podemos, então, finalmente montar a relação de recursão de :
Se ,
Senão, , onde é a soma dos números na linha desde a coluna até a coluna . No entanto, a complexidade da função é exponencial, e logo, não passa nas restrições do problema. Para tornar a complexidade aceitável, utilizaremos duas técnicas adicionais:
1. Podemos conseguir em , com pré-cálculo em , da seguinte maneira: Primeiro, vamos definir uma matriz como sendo a soma dos números na linha desde a coluna até a coluna . Inicialmente, , para todo tal que . Então, , com . Portanto, é possÃvel conseguir em após o pré-cálculo, já que , ou seja, .
2. Finalmente, usaremos uma matriz chamada que irá guardar todos os estados que já foram previamente calculados na recursão (essa técnica é conhecida como programação dinâmica). Assim, evitamos que um estado seja calculado mais de uma vez, tornando a complexidade da função , já que . Obteremos então a resposta do problema chamando .
Segue o código para melhor entendimento.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Piramide - Fase 1 P1 - 2018 | |
//Por Lucio Cardoso | |
//Complexidade: O(n²) | |
#include <bits/stdc++.h> | |
using namespace std; | |
const int MAXN = 110; | |
int num[MAXN][MAXN], soma[MAXN][MAXN], dp[MAXN][MAXN], n; | |
// pre-cálculo em O(n^2) para encontrar soma[][] | |
void pre(void) | |
{ | |
for (int i = 1; i <= n; i++) | |
for (int j = 1; j <= n; j++) | |
soma[i][j] = soma[i][j-1]+num[i][j]; | |
} | |
// recursão em O(n^2) | |
int f(int k, int j) | |
{ | |
if (k == 1) return num[1][j]; // caso base | |
if (dp[k][j] != -1) return dp[k][j]; // se f(k,j) já foi calculado | |
int s = soma[k][j+k-1]-soma[k][j-1]; // soma na linha atual | |
int caso1 = f(k-1, j); | |
int caso2 = f(k-1, j+1); | |
// salvo em dp a resposta de f(k, j) e a retorno | |
return dp[k][j] = s+min(caso1, caso2); | |
} | |
int main(void) | |
{ | |
cin >> n; | |
for (int i = 1; i <= n; i++) | |
for (int j = 1; j <= n; j++) | |
cin >> num[i][j]; | |
pre(); // faço o pré-cálculo | |
// inicializo dp com um valor que nunca será resposta, digamos -1 | |
memset(dp, -1, sizeof dp); | |
cout << f(n, 1) << "\n"; // imprimo a resposta, começando na base | |
} |