F. Editorial para Dois (resposta de dois pontos + arrependimento e ganância)
1. Problema
Dado um nnn ekkk e um comprimentonnmatriz n . agora dennEntre n números, escolhakkK números são chamados de subsequências. Em seguida, divida esta subsequência em duas partes, denotadas como subsequência 1 e subsequência 2. Então, tanto a subsequência 1 quanto a subsequência 2 têm uma soma correspondente. Essas duas somas podem ser comparadas a um valor máximo. Agora o que queremos éo valor mínimo do valor máximo.
2. Análise
Aqui está uma rotina muito comum: quando a questão nos pede para encontrar o valor mínimo do valor máximo ou o valor máximo do valor mínimo, geralmente usamos a dicotomia para resolvê-la.
Nós dividimos a resposta final aqui.
Por dois pontos, a dificuldade está em checar checarA escrita da função check .
Nesta questão, marque marqueA função da função de verificação é julgar meio meiono processo de dicotomiaÉ o valor médio razoável.
Então isso escolhe no máximo k 1 k1O processo dos números k 1 usaarrependimento eganância. A ideia de arrependimento e ganância é quando a soma dos números selecionados é menor quemeio meioQuando for meio , escolha o maior número possível de números, quando for maior quemeio meioQuando mid , o valor máximo dos números selecionados é excluído, o objetivo é deixar mais espaço para que mais números sejam selecionados, e esse processo de seleção do valor máximo pode ser otimizado com um grande heap raiz.
Além disso, a localização da divisão de prefixo e sufixo na figura é incerta, portanto, precisamos enumerar todas as localizações de divisão para encontrar uma solução viável.
Portanto, podemos primeiro pré-processar os números mais selecionados k 1 , k 2 k1,k2 entre todos os prefixos e sufixos usando arrependimento e ganância.k 1 ,k 2 . Em seguida, enumere as posições de divisão e julgue se existe um grupo dek 1 + k 2 ≥ k k1+k2 \geq kk 1+k2_ _≥k .
3. Código
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
bool check(int maxv, int n, vector<int>a, int k)
{
vector<int>f(n + 1, 0), g(n + 1, 0);
priority_queue<int>q, qq;
int sum = 0;
for(int i = 0; i < n; i ++)
{
if(sum + a[i] <= maxv)
{
sum += a[i];
q.push(a[i]);
f[i + 1] = f[i] + 1;
}
else
{
q.push(a[i]);
sum += a[i];
sum -= q.top();
q.pop();
f[i + 1] = f[i];
}
}
sum = 0;
reverse(a.begin(), a.end());
for(int i = 0; i < n; i ++)
{
if(sum + a[i] <= maxv)
{
sum += a[i];
qq.push(a[i]);
g[i + 1] = g[i] + 1;
}
else
{
sum += a[i];
qq.push(a[i]);
sum -= qq.top();
qq.pop();
g[i + 1] = g[i];
}
}
for(int i = 1; i <= n; i ++ )
{
if(f[i] + g[n - i] >= k)
return true;
}
return false;
}
void solve()
{
int n, k;
cin >> n >> k;
vector<int>a(n);
int sum = 0;
for(int i = 0; i < n; i ++)
{
cin >> a[i];
sum += a[i];
}
int l = 0, r = sum;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid, n, a, k))
r = mid;
else
l = mid + 1;
}
cout << l << endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
solve();
}