Lembre-se das questões do teste escrito de uma determinada residência

A prova escrita online de uma determinada residência é legal, então enviei para ver se alguém pode me dar alguma dica de como resolver o problema;

1. Tópico 1

1.1 Pergunta

Existem duas matrizes com comprimento n (1 - 5.000), ou seja, a e b (1 - 1.000.0000). O grau de preferência é definido como a soma de ai*bi. Você pode escolher um intervalo de b e invertê-lo uma vez para
perguntar para o grau máximo de preferência
. Exemplo:
3
10 1 1
1 10 1
Saída:
102
Explicação:
O intervalo da matriz b invertida é [1, 2], após invertê-la é 10 1 1, uma matriz é 10 1 1, o os bits correspondentes são multiplicados e somados até 102;

1.2 Ideias de soluções violentas

Idéia:
enumerar os intervalos, para cada intervalo, inverter os elementos do intervalo na matriz, calcular o grau semelhante após a inversão e atualizar o valor máximo e, finalmente, gerar o grau semelhante máximo. A complexidade do tempo é o código O (n ^ 3)
:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    
    
    int n;
    cin >> n;

    vector<int> a(n);
    vector<int> b(n);
    for (int i = 0; i < n; i++) {
    
    
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
    
    
        cin >> b[i];
    }

    // 计算原始的喜欢程度
    long long ans = 0;
    for (int i = 0; i < n; i++) {
    
    
        ans += (long long)a[i] * b[i];
    }

    // 枚举区间,计算翻转区间后的喜欢程度
    for (int i = 0; i < n; i++) {
    
    
        for (int j = i; j < n; j++) {
    
    
            // 翻转区间
            reverse(a.begin() + i, a.begin() + j + 1);

            // 计算喜欢程度
            long long cur = 0;
            for (int k = 0; k < n; k++) {
    
    
                cur += (long long)a[k] * b[k];
            }

            // 更新最大值
            ans = max(ans, cur);

            // 恢复原数组
            reverse(a.begin() + i, a.begin() + j + 1);
        }
    }

    cout << ans << endl;

    return 0;
}

1.3 Ideias de otimização para geração de IA

Idéia:
posso fornecer uma solução baseada em algoritmo ganancioso e otimização de soma de prefixos, com complexidade de tempo de O (n).

Primeiro, podemos converter o produto ai bi em (a+b) (ab), onde a = (ai+bi)/2 e b = (ai-bi)/2. Precisamos apenas considerar os maiores (a+b) e (ab).

Tomando (a+b) como exemplo, podemos primeiro calcular a diferença entre todos os dois elementos adjacentes diff[i] = (a[i+1]+b[i+1]) - (a[i]+b [ i]), então você pode julgar se a posição do intervalo precisa ser invertida com base no sinal da diferença. Especificamente, definimos sum1 = a[1]+b[1], sum2 = a[1]-b[1] e, em seguida, fazemos um loop da posição i=2:

  • Se diff[i] > 0, significa que a[i]+b[i] é maior que a[i-1]+b[i-1], o que significa que há melhores escolhas para os intervalos candidatos subsequentes. Registramos maxSum = max(maxSum, sum1+sum2) e marcamos o intervalo [start, i] que precisa ser invertido e atualizamos sum1 e sum2 ao mesmo tempo.
  • Se diff[i] <= 0, significa que a posição atual i-1 pode precisar ser adicionada ao intervalo candidato e só precisamos atualizar sum1 e sum2.

Para a atualização de maxSum, se o intervalo atual que precisa ser invertido for [início, fim], então podemos inverter a[início], b[início] e a[fim], b[fim], ou seja, trocar a[start] e a[end], troque b[start] e b[end] para obter o novo (maxSum, maxA, maxB). Observe que precisamos apenas selecionar o segmento com o maior a+b no intervalo que precisa ser invertido, mas não precisamos selecionar o maior intervalo que precisa ser invertido. Porque é possível que a diferença entre alguns intervalos seja muito pequena e seja invertida muitas vezes, resultando em alta complexidade de tempo.

Finalmente, precisamos calcular a existência do intervalo invertido [início, fim] novamente e realizar a otimização da soma do prefixo em a e b, respectivamente, para calcular rapidamente a soma do intervalo. Especificamente, calculamos os prefixos e sa e sb de a e b respectivamente, e então o grau máximo de preferência n é igual a a e sa no intervalo [1, start-1], mais a e sa no intervalo [start, fim] O valor absoluto da diferença, mais a e sa no intervalo [fim+1, n], é multiplicado por b e sb. Cálculos semelhantes podem obter a resposta.

O código é implementado da seguinte forma:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
int n, a[MAXN], b[MAXN];
long long sa[MAXN], sb[MAXN];
int diff[MAXN], pos[MAXN];
long long maxSum, maxA, maxB;
void solve()
{
    
    
    sa[0] = sb[0] = pos[0] = 0;
    for (int i = 1; i <= n; ++i) {
    
    
        cin >> a[i] >> b[i];
        sa[i] = sa[i - 1] + a[i];
        sb[i] = sb[i - 1] + b[i];
        pos[i] = i - 1;
        diff[i] = a[i] + b[i] - a[i-1] - b[i-1];
    }
    maxSum = sa[1] + sb[1] + sa[n] - sa[1] + sb[n] - sb[1];
    maxA = sa[1] - sb[1];
    maxB = sb[1] - sa[1];
    int start = 1, end = 0;
    long long sum1 = sa[1] + sb[1], sum2 = sa[1] - sb[1];
    for (int i = 2; i <= n; ++i) {
    
    
        if (diff[i] > 0) {
    
    
            long long tmpSum1 = sum1 + sa[i] - sa[start] + sb[n] - sb[i-1];
            long long tmpSum2 = sum2 + sa[i] - sa[start] - sb[n] + sb[i-1];
            if (tmpSum1 + tmpSum2 > maxSum) {
    
    
                maxSum = tmpSum1 + tmpSum2;
                maxA = tmpSum1 / 2;
                maxB = tmpSum2 / 2;
                if (i <= n - 1 && diff[i+1] <= 0 && sa[i+1]-sa[start] > sb[n]-sb[i]) {
    
    
                    ++i;
                    tmpSum1 += sa[i] - sa[start] - sb[n] + sb[i-1];
                    tmpSum2 += sb[n] - sb[i-1] - sa[i] + sa[start];
                }
                start = pos[i] + 2;
                end = i;
            }
            sum1 += sa[i] - sa[start] + sb[i] - sb[start-1];
            sum2 += sa[i] - sa[start] - sb[i] + sb[start-1];
        } else {
    
    
            sum1 += sa[i] - sa[i-1];
            sum2 += sb[i] - sb[i-1];
            pos[i] = pos[i-1];
        }
    }
    sum1 = sa[n] - sa[start-1];
    sum2 = sb[n] - sb[start-1];
    for (int i = n; i >= end+1; --i) {
    
    
        diff[i] = a[i] + b[i] - a[i-1] - b[i-1];
        if (diff[i] <= 0) {
    
    
            sum1 -= sa[i] - sa[end+1];
            sum2 -= sb[i] - sb[end+1];
        }
    }
    long long answer = abs(sum1*maxB) + abs(sum2*maxA);
    cout << answer << endl;
}
int main()
{
    
    
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    solve();
    return 0;
}

No código, usamos sa e sb para armazenar a soma dos prefixos de a e b, diff armazena a diferença entre dois elementos adjacentes e pos armazena o ponto final esquerdo do intervalo que precisa ser invertido. Para atualizar maxSum, também precisamos considerar se o intervalo atualmente selecionado pode ser mesclado com intervalos adjacentes subsequentes para obter uma escolha melhor.

Finalmente, podemos realizar a otimização da soma do prefixo em a e b, respectivamente, para calcular rapidamente a soma do intervalo. Ao calcular a simpatia, também precisamos prestar atenção ao valor absoluto.

Em resumo, a complexidade de tempo deste algoritmo ganancioso é O(n), que é mais eficiente que os métodos de força bruta e métodos de programação dinâmica, e pode resolver problemas com grandes tamanhos de dados.

mmd, o código para a ideia de otimização não parece certo, está entorpecido.

2. Simule questões de criptografia e descriptografia

Pergunta:
Para uma string: kingsoft, o vovô gosta de criptografá-la. O método de criptografia é pegar primeiro a cabeça, depois a cauda, ​​até terminar. Depois de
criptografar de acordo com o método de criptografia do vovô, fica assim: ktifnogs, agora o vovô transmitiu para você, você precisa descriptografar e gerar uma string.
Não pensei em nenhuma otimização para esta questão, então apenas inverti o método de criptografia para obtê-la.O que preciso prestar atenção é o problema de obter caracteres pares e ímpares, e nada mais;

3. Questões de programação dinâmica

esquecer

Acho que você gosta

Origin blog.csdn.net/BinBinCome/article/details/131025687
Recomendado
Clasificación