题目链接
对于一个区间([x,y]),设这个区间的总和为(S)
那么我们在前缀和(设为(sum[i]))的意义上考虑到原操作其实就是(sum[x−1]+=S) , (sum[x]+S−S) , (sum[y]−=S) , (sum[y+1]+S−S)。
而且我们注意到,本来就有(sum[x−1]+S==sum[y]),所以观察到其实原操作只是单纯的交换了一下(sum[x−1])和(sum[y])而已,而且这个([x,y])区间任意选择,故原题已经可以改为:
给一个前缀和序列,可以在其中任意交换2个数,最后让这个序列变为单调递增的。
注意:在前缀和序列里不能有负数和相等的,若有就输出-1
--摘自洛谷题解
离散化一下贪心交换就好了。。这个贪心实现有难度
#include <cstdio>
#include <iostream>
#define re register
using namespace std;
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin);fclose(stdout);
const int MAXN = 100010;
inline int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
}
int n, ans, num;
int a[MAXN], p[MAXN], s[MAXN];
int cmp(int x, int y){
return a[x] < a[y];
}
int main(){
Open("sequence");
ans = n = read();
for(re int i = 1; i <= n; ++i){
a[i] = read() + a[i - 1];
p[i] = i;
if(a[i] <= 0){
printf("-1
");
return 0;
}
}
for(int i = 1; i <= n; ++i)
if(a[i] == a[i - 1]){
printf("-1
");
return 0;
}
sort(p + 1, p + n + 1, cmp);
for(int i = 1; i <= n; ++i)
a[p[i]] = i;
for(int i = 1; i <= n; ++i)
if(i == a[i])
--ans;
else swap(p[a[i]], p[i]), swap(a[p[a[i]]], a[i]);
printf("%d
", ans);
return 0;
}