分析
将一段区间[l, r]变成最大,可以遵循以下规则,先对第一个数进行操作,如果他是0, 那么会变成1,所以不进行操作,如果不是0,就要进行操作,让它变成0,只有这样才能让他后面的元素得到更大的结果,所以以此类推,可以让整个区间变成0,1,2,3,…r - l,对这种区间再次进行操作,就可以变成r - l + 1, r - l + 1, …, r - l + 1。
可以枚举所有情况,去看哪种情况能够得到最大的和,然后可以对这种最大的方案进行操作模拟,得到最后的数组,可以通过dfs进行模拟过程,找出过程中需要进行操作的区间。
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n;
cin >> n;
vector<int> a(n);
for(int i = 0; i < n; i ++) cin >> a[i];
ll maxn = 0;
int x = 0;
for(int i = 0; i < (1 << n); i ++) {
ll sum = 0;
for(int l = 0; l < n; l ++) {
if((i >> l) & 1) {
int r = l + 1;
while(r < n && ((i >> r) & 1)) r ++;
r --;
sum += (r - l + 1) * (r - l + 1);
l = r;
}
else sum += a[l];
}
if(maxn < sum) {
maxn = sum;
x = i;
}
}
vector<pair<int, int>> ans;
auto cal = [&](int l, int r) {
map<int, int> cnt;
ans.push_back({l + 1, r + 1});
for(int i = l; i <= r; i ++) {
cnt[a[i]] ++;
}
int mex = 0;
while(cnt[mex]) mex ++;
for(int i = l; i <= r; i ++) a[i] = mex;
};
auto build = [&](auto self, int l, int r) -> void {
//cout << l << ' ' << r << '-' << endl;
if(l == r) {
if(a[r]) {
cal(l, r);
}
return ;
}
self(self, l, r - 1);
if(a[r] != r - l) {
cal(l, r);
self(self, l, r - 1);
}
};
for(int l = 0; l < n; l ++) {
if((x >> l) & 1) {
int r = l + 1;
while(r < n && ((x >> r) & 1)) r ++;
r --;
build(build, l, r);
cal(l, r);
l = r;
}
}
cout << maxn << ' ' << ans.size() << "\n";
for(auto j: ans) cout << j.first << ' ' << j.second << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
T = 1;//cin >> T;
while(T --) {
solve();
}
}