码迷,mamicode.com
首页 > 其他好文 > 详细

北大ACM3061——Subsequence

时间:2015-05-05 08:59:46      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:acm   北大   

题目大概的意思是:给你一个整数数列,从中找出最小连续子序列的和不小于整数S。

数列最小为10,最大为100000,用暴力法估计会超时,我没有试过。

这里,我将用两种方法来求解这一题,一个时间复杂度为nlogn,另一个时间复杂度为n,不过两个提交了,时间都是79MS。没多大的区别。

1.时间复杂度为nlogn的方法:

主要的思路是用一个数组 sum 算出数列的前 i+1 个数的和,(i从0到n),然后每一个数列sum的每一个都加上S,再在数组sum中查找不小于sum[i] + S的位置ans。ans - i 就是不小于S的序列的长度,不断更新ans - i,就可以将解求出。

algorithm  中有一个函数lower_bound 就是求解一段数组中不小于一个数的下标。

下面的是AC的代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[100005], sum[100005];

int min(int x, int y)
{
	return x > y ? y : x;
}
void solve(int n, int s)
{
	int i, j;
	for(i = 0; i < n; i++)                //计算前i+1个数的和
		sum[i + 1] = sum[i] + a[i];
	if(sum[n] < s)                        //全部数之和小于s,直接输出0
		printf("0\n");
	else
	{
		int res = n;
		for(j = 0; sum[j] + s <= sum[n]; j++) //在sum数组中,查找不小于s + sum【j】的位置,不断的更新
		{
			int ans = lower_bound(sum + j, sum + n, sum[j] + s) - sum;  //返回不小于s + sum【j】的位置
			res = min(res, ans - j);                                    //比较res与ans - j谁小。不断更新
		}
		printf("%d\n", res);
	}
}

int main()
{
	int t, n, s;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &n, &s);
		memset(sum, 0, sizeof(sum));         //初始化,
		for(int i = 0; i < n; i++)
			scanf("%d", &a[i]);
		solve(n, s);
	}
	return 0;
}

2.时间复杂度为n的方法:

主要的思路就是:设置两个位置的标志,一个s为不小于m的序列的起始位置,一个t为不小于m的序列的末尾位置。一开始s =  t = 0,设置一个序列和sum = 0;开始 sum += a【t++】直到 sum > m,算出序列长度 t - s;然后sum - a【s++】;看sum 是否还大于m,不大于,就继续加上a【t++】,否则则更新序列长度,sum - a【s++】;

不断的这样更新,就可以求出最小的序列长度。

对于文字不是很理解,可以看下面的图示。

技术分享

下面的是AC的另一段代码:

#include <iostream>
#include <cstdio>
using namespace std;

int a[100005];


int min(int x, int y)
{
	return x > y ? y : x;
}

void solve(int n, int m)
{
	int res = n + 1;
	int s, t, sum;
	s = t = sum = 0;
	while(1)
	{
		while(t < n && sum < m)          //累加a数组,直到sum > m
		{
			sum += a[t++];
		}
		if(sum < m)                       //如果总和小于m,则退出
			break;
		res = min(res, t - s);            //算出序列长度
		sum -= a[s++];                    //序列起始位置去掉一个,再进行循环
	}
	if(res > n)
		res = 0;
	printf("%d\n", res);
}

int main()
{
	int t, n, s;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &n, &s);
		for(int i = 0; i < n; i++)
			scanf("%d", &a[i]);
		solve(n, s);
	}
	return 0;
}


北大ACM3061——Subsequence

标签:acm   北大   

原文地址:http://blog.csdn.net/qq_25425023/article/details/45485667

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!