比較經典的一個題目,考察的既不是滑動窗口也不是動態規劃,考察的其實是二分法,二分的範圍是從序列中的最大值到序列的所有的元素之和。每次二分計算出對應的mid值,然後判斷是否能夠將序列劃分成爲不超過k個部分,每個部分的值都不超過mid,如果可以,那麼就繼續縮小範圍,也就是降低下限進行判斷,如果不可以的話,那麼就放大範圍也就是提高下限進行判斷,得出最終的結果之後,就開始對數列進行劃分,這裏要注意一個點,題目要求越靠近前方的部分的和就要越小,所以我們從後向前加‘/’,同時要注意剩餘的斜槓數等於剩下的爲劃分的數字的個數。其他的就比較簡單了,具體實現見如下代碼:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
using namespace std;
int N;
typedef long long LL;
vector<LL> data;
vector<int> ind;
int solve(LL up){
int ans = 1;
LL temp = 0;
for (int i = 0; i < data.size(); i++){
if (temp + data[i] <= up){
temp += data[i];
}
else{
ans++;
temp = data[i];
}
}
return ans;
}
void getRes(LL up,int k){
LL temp = 0;
for (int i = data.size() - 1; i >= 0; i--){
if (temp + data[i] > up || i + 1 < k){
ind[i] = 1;
k--;
temp = data[i];
}
else
temp += data[i];
}
for (int i = 0; i < data.size() - 1; i++){
cout << data[i] << " ";
if (ind[i]) cout << "/ ";
}
cout << data[data.size() - 1] << endl;
}
int main(){
cin >> N;
while (N--){
int m, k;
cin >> m >> k;
data.clear();
ind.clear();
LL sum = 0;
LL maxn = -1;
for (int i = 0; i < m; i++){
long long t;
cin >> t;
data.push_back(t);
ind.push_back(0);
sum += t;
maxn = max(maxn, t);
}
LL L = maxn, R = sum;
while (L < R){
LL mid = L + (R - L) / 2;
if (solve(mid) <= k) R = mid;
else L = mid + 1;
}
getRes(L,k);
}
return 0;
}