洛谷P1667/[10.22 模拟赛] 数列 (思维+模拟)
洛谷P1667 數列
題目描述
給定一個長度是n的數列A,我們稱一個數列是完美的,當且僅當對于其任意連續子序列的和都是正的。現在你有一個操作可以改變數列,選擇一個區間[X,Y]滿足\(A_X +A_{X+1} +…+ A_Y<0,1<X<=Y<n,\)令\(S=A_X +A_{X+1} +…+ A_Y\),對于\(A_{X-1}\)和\(A_{Y+1}\)分別加上S,\(A_X\)和\(A_Y\)分別減去S(如果X=Y就減兩次)。問最少幾次這樣的操作使得最終數列是完美的。
輸入輸出格式
輸入格式:
第一行一個數n,以下n個數。
【數據規模】
對于20%的數據,滿足1≤N≤5;
對于100%的數據,滿足\(1≤N≤10^5; 1≤|A[i]|≤2^31-1.\)
輸出格式:
一個數表示最少的操作次數,如果無解輸出-1。
輸入輸出樣例
輸入樣例#1:
5
13
-3
-4
-5
62
輸出樣例#1:
2
說明
【樣例解釋】
首先選擇區間[2,4],之后數列變成1,9,-4,7,50,然后選擇[3,3],數列變成1,5,4,3,50
Solution
按照題目意思,我們令\(T=sum[r]-sum[l-1]\),其中sum為a的前綴和
那么會有a[l-1]+=T,a[r+1]+=T,a[l]-=T,a[r]-=T,實際上對于sum[l]和sum[r+1]是沒有變化的,而sum[l-1]會增加T,sum[r]會減少T,實際上就是sum[l-1]和sum[r]交換了位置
由于題目要求任意\(a_i\)均為正數,所以前綴和必須嚴格上升,那么很容易看出\(sum_i<=0\)或者是\(i<j\)并且\(sum_i=sum_j\)無解
正常情況下,我們要求交換次數,把前綴和離散后,它是第幾小就該到哪去,所以就是模擬交換并統計次數就可以了
Code
#include<bits/stdc++.h> #define rg register #define il inline #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define lol long long #define in(i) (i=read()) using namespace std;const lol N=2e5+10;lol read() {lol ans=0,f=1; char i=getchar();while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();return ans*=f; }lol n,sum[N],id[N],AQ[N];bool cmp(lol a,lol b) {return sum[a]<sum[b];}int main() {//freopen("bsum.in","r",stdin);//freopen("bsum.out","w",stdout);in(n);for(lol i=1;i<=n;i++) {in(sum[i]),id[i]=i;sum[i]+=sum[i-1],AQ[i]=sum[i];}sort(AQ+1,AQ+1+n);for(lol i=1;i<n;i++) {if(AQ[1]<=0 || AQ[i]==AQ[i+1])cout<<-1<<endl,exit(0);}sort(id+1,id+1+n,cmp);for(lol i=1;i<=n;i++) sum[id[i]]=i;lol ans=n;for(lol i=1;i<=n;i++) {if(sum[i]==i) ans--;else {swap(id[i],id[sum[i]]);swap(sum[i],sum[id[sum[i]]]);}}cout<<ans<<endl; }轉載于:https://www.cnblogs.com/real-l/p/9832337.html
總結
以上是生活随笔為你收集整理的洛谷P1667/[10.22 模拟赛] 数列 (思维+模拟)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 21 ——合并两个有序
- 下一篇: 修改VS2017新建类模板文件添加注释