给定一个序列a[i],取出一段连续的子序列,使得子序列的和的绝对值最小。
N<=10^6,a[i]<=10^9。
sol:先求出前缀和,我们考虑到,任何一个子序列和的绝对值,都可以表示为|s[x]-s[y]|(x大于y),那么任何有一个|s[x]-s[y]|(x大于y),都对应一个子序列和的绝对值。所以,我们只要找出一组(x,y),使得|s[x]-s[y]|最小即可。故,可对前缀和排序后,依次比较|s[i]-s[i+1]的绝对值,从中选择最小的。
如a[i]:2 8 -20 5 10
s[i]:0 2 10 -10 -5 5(s[0]=0要参与进来排序和后续比较运算)
排序后s[i]:-10 -5 0 2 5 10
|s[i]-s[i+1|]:5 5 2 3 5 ,最小2为本题答案。
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #define INF 1000005 6 using namespace std; 7 int num[INF],sum[INF]; 8 int main() 9 { 10 int N; 11 scanf("%d",&N); 12 for(int i=1;i<=N;i++) 13 scanf("%d",&num[i]); 14 sum[0]=0; 15 for (int i=1;i<=N;i++) 16 sum[i]+=sum[i-1]+num[i]; 17 sort(sum,sum+N+1); //注意,这里s[0]要参与排序和进行后续的比较运算。 18 int minx=INF; 19 for(int i=0;i<N;i++) 20 if(abs(sum[i]-sum[i+1])<minx) minx=abs(sum[i]-sum[i+1]); 21 printf("%d ",minx); 22 return 0; 23 }