HDU 4223 Dynamic Programming?(最小连续子序列和的绝对值O(NlogN))

时间:2023-03-08 20:33:01
HDU 4223 Dynamic Programming?(最小连续子序列和的绝对值O(NlogN))

传送门

Description

Dynamic Programming, short for DP, is the favorite of iSea. It is a method for solving complex problems by breaking them down into simpler sub-problems. It is applicable to problems exhibiting the properties of overlapping sub-problems which are only slightly smaller and optimal substructure.
Ok, here is the problem. Given an array with N integers, find a continuous subsequence whose sum’s absolute value is the smallest. Very typical DP problem, right?

Input

The first line contains a single integer T, indicating the number of test cases.
Each test case includes an integer N. Then a line with N integers Ai follows.

Technical Specification
1. 1 <= T <= 100
2. 1 <= N <= 1 000
3. -100 000 <= Ai <= 100 000

Output

For each test case, output the case number first, then the smallest absolute value of sum.

Sample Input

2 2 1 -1 4 1 2 1 -2

Sample Output

Case 1: 0 Case 2: 1

思路

题意虽然是动态规划,但是不用动态规划也可以做,并且复杂度大大降低,存储序列的前缀和,那么我们可以知道绝对值最小的子段和就是前缀数组两两相减中绝对值最小者。因此,我们将序列的前缀数组排序,此时用桶排序,那么复杂度可以降低到O(N),快排的话复杂度降低到O(NlogN),然后用O(N)的复杂度扫一遍找出相邻差最小的值。注意,在前缀数组中,我们要手动加入一个前缀和为0的值,以此来保证结果的正确性。假设子段[1:3]的值为-1,子段[1:5]的值为1,如果不加入一个0,很可能得出的结果为2,当然了,加些预处理的话可以避免这个问题,但是还是手动加一个前缀和为0的值这样来得简单。也可以这么理解,子段和的绝对值最小,那就是离0最近的值。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;

int main()
{
    int T,Case = 0;
    scanf("%d",&T);
    while (T--)
    {
        int N,tmp,sum[maxn] = {0};
        scanf("%d",&N);
        for (int i = 1;i <= N;i++)
        {
            scanf("%d",&tmp);
            sum[i] = sum[i-1] + tmp;
        }
        sort(sum,sum+N+1);
        int res = sum[1]-sum[0];
        for (int i = 0;i < N;i++)
        {
            res = min(res,abs(sum[i+1]-sum[i]));
        }
        printf("Case %d: %d\n",++Case,res);
    }
    return 0;
}