您的位置:首页 > 其它

UVALive2678子序列

2014-01-18 17:03 281 查看
UVALive2678

http://122.207.68.93:9090/csuacmtrain/problem/viewProblem.action?id=453§

【题目描述】:n个正整数组成的序列。给定整数S,求长度最短的连续序列,使他们的和大于等于S。

【算法分析】:

【二分】:

全是正整数,保证取的连续序列长度越长,和越可能大于等于S,所以满足二分的单调递增的条件,而这里,我们要找的最优解是最小的长度,就是和刚刚好大于等于S的区间长度。

【区间和优化到O(N)】:

使用C[i]数组,做差求和。方法不细说。要求自己,以后遇到区间求和问题,自然就要想到这个。

【运筹分析】:

决策方案:所有区间段,sigm(n+(n-1).......+1) == O(n^2)注意n<=10^5

限制条件:累和大于等于S

最优评判标准:区间长度最小

【完整代码】:

#include<iostream>

#include<stdio.h>

#include<string.h>

#include<algorithm>

#include<stdlib.h>

#include<math.h>

#include<queue>

#include<vector>

#include<map>

#define MAXN 100000+5

#define MAXM 20000+5

#define oo 9556531

#define eps 0.000001

#define PI acos(-1.0)//这个精确度高一些

#define REP1(i,an) for(int i=0;i<=(n);i++)

#define REP2(i,n) for(int i=1;i<=(n);i++)

using namespace std;

//这道题不是dp,而是二分,一是因为dp本身会超时,二是连续的状态是单调递增的

int A[MAXN];

int C[MAXN];

int n,s;

bool isok(int l)

{

for(int i=l;i<=n;i++)

if(C[i]-C[i-l]>=s) return true;//优化到O(n)

return false;

}

int main()

{

while(cin>>n>>s)

{

C[0]=0;

for(int i=1;i<=n;i++)

{

cin>>A[i];

C[i]=C[i-1]+A[i];

}

int l=1,r=n+1;

while(l<r)//边界条件,保证能够跳出循环,找不到极值也可,画状态图确定

{

int m=(l+r)/2;

if (isok(m)) r=m;else l=m+1;//根据除2取左的特点,保证能取到极值点

}

if (isok(l)) cout<<l<<endl;else cout<<0<<endl;

}

return 0;

}


【关键词】:二分,思维

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: