51nod---Subsequence (子序列)

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.
Input
The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.
Output
For each the case the program has to print the result on separate line of the output file.if no answer, print 0.
Sample Input

2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5

Sample Output

2
3

大体意思如下:
有n个正整数组成一个序列
给定整数S 求长度最短的连续序列 使它们的和大于或等于S
连续子序列和大于等于 s 并且长度最短
思路:
前缀和 和 二分法的结合
如果写两个循环标记下边的变化,会超限,就应该想到一些技巧性的思路

/*
用到了前缀和+二分法,刚接触这两个算法,花了好久才似懂非懂,就先整理下来,便于以后理解
看到连续子序列的和,就会想到用前缀和来求出来前几项的和,然后就开始找最短的长度
对于一个下标 i,用二分法去求他前边哪一个下标可以实现 长度最短并且和大于等于 s
(说起来有点不清楚,原谅我菜没有办法很好的解释)
*/
#include
#include
#include
#include
#include
using namespace std;
typedef long long int LL;
#define INF 0x3f3f3f3f
LL sum[100002];
int f(LL a,LL s,LL r)  // 二分法
{
    LL l=0;
    LL mid=0;
    while(l=s) // 如果该下标-中点的值还大与 s的话,
					        //说明不一定是最短的,所以左端点要右移
            l=mid+1;
        else  // 如果小于 s的话,说明减多了,
              //那么右端点左移,就会实现中点的下标往左移(mid=(l+r)/2;
            r=mid;
    }
    return l;// 返回的是 左端点的值
}
int main()
{
    LL n,t,s;
    LL i,j,b;
    LL minn;
    scanf("%lld",&t);
    while(t--){
        minn=INF;
        memset(sum,0,sizeof(sum));
        scanf("%lld %lld",&n,&s);
        for(i=1;i<=n;i++){
            scanf("%lld",&b);
            sum[i]=sum[i-1]+b;
        }
        for(j=1;j<=n;j++){
            LL flag=f(j,s,j-1);
            if(flag>0)  // 如果返回值是 0的话,代表 l 根本没有移动,
		  //说明连一开始  l

你可能感兴趣的:(ACM,----,题解,ACM,----,做题技巧)