题目大意:给你n个银行中的存款(负值表示借贷),是成环的,1跟n相接,这n个数的和为0。可以从i向i的相邻两侧转移存款,问你最少转移多少次,可以让所有银行的存款都为0。
解题思路:n个数的和为0,假设是由k个和为0的区间组成的。假设这些区间的长度为li,那么长度为li的区间需要li-1次转移。那么总共需要l1-1+l2-1+l3-1...+lk-1次转移,因为l1+l2+l3...lk=n,所以总共需要n-k次转移,这个k就是区间和为0的区间个数。我们通过求前缀和sum来统计区间和为0的个数。当sum[i] = sum[j]时,我们知道a[i+1]+...a[j]为0,这个区间和为0。所以我们记录sum=X出现的次数,n-time[X]来更新答案。
此题是均分纸牌(NOIP2002)强化(弱化?)版,此题1与n间可互换
C++自带离散化
排序里面MID没用INT64交了十多次终生遗憾
1 var c,d:array[0..200000]of longint; 2 a,s:array[0..200000]of int64; 3 n,i,ans:longint; 4 t:int64; 5 6 function min(x,y:longint):longint; 7 begin 8 if x<y then exit(x); 9 exit(y); 10 end; 11 12 procedure qsort(l,r:longint); 13 var i,j:longint; 14 mid:int64; 15 begin 16 i:=l; j:=r; mid:=s[(l+r) div 2]; 17 repeat 18 while mid>s[i] do inc(i); 19 while mid<s[j] do dec(j); 20 if i<=j then 21 begin 22 t:=s[i]; s[i]:=s[j]; s[j]:=t; 23 inc(i); dec(j); 24 end; 25 until i>j; 26 if l<j then qsort(l,j); 27 if i<r then qsort(i,r); 28 end; 29 30 begin 31 read(n); 32 // fillchar(s,sizeof(s),0); 33 // fillchar(c,sizeof(c),0); 34 // fillchar(d,sizeof(d),0); 35 // 36 for i:=1 to n do read(a[i]); 37 ans:=n-1; 38 for i:=1 to n do s[i]:=s[i-1]+a[i]; 39 40 qsort(1,n); 41 for i:=1 to n do 42 if (i=1)or(s[i]>s[i-1]) then c[i]:=c[i-1]+1 43 else c[i]:=c[i-1]; 44 45 for i:=1 to n do inc(d[c[i]]); 46 for i:=1 to n do ans:=min(ans,n-d[i]); 47 writeln(ans); 48 49 end.