首页 > 代码库 > LA 2678 Subsequence(二分查找)
LA 2678 Subsequence(二分查找)
题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=679
解题报告:给定一个正整数的序列,和一个S,求长度最短的子序列,使它们的和大于或等于S。序列长度n <= 100000
很明显,如果枚举起点和终点的话,时间复杂度是O(n^3),不行。怎么能在O(1)时间求出一个子序列的和是多少呢,可以用另一个数组sum[i],意义是第一个到
第i个数的和是sum[i],这样的话就可以做到在O(1)时间求出一个子序列的和,但这样还是不够,我的做法是只枚举子序列的终点,然后找到一个j使得sum[j] >= sum[i] - S,那么这个子序列的长度就是i - j + 1,因为sum[i]是递增的,在查找j的位置的时候用二分查找,所以,这样就把时间复杂度降到了n*log2(n),就可以过了。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int maxn = 100005; 7 int A[maxn],sum[maxn]; 8 9 int find(int *B,int l,int r,int d)10 {11 while(l < r)12 {13 int mid = (l + r) >> 1;14 if(d <= B[mid]) r = mid;15 else l = mid + 1;16 }17 return l;18 }19 20 int main()21 {22 int n,s;23 while(scanf("%d%d",&n,&s)!=EOF)24 {25 int k = 0;26 sum[0] = 0;27 for(int i = 1;i <= n;++i)28 {29 scanf("%d",&A[i]);30 sum[i] = sum[i-1] + A[i];31 if(k == 0 && sum[i] >= s) k = i;32 }33 int ans = 0x7fffffff;34 for(int i = k;i <= n;++i)35 {36 int t = find(sum,1,i,sum[i] - s);37 if(sum[t] > sum[i]-s) t--;38 ans = min(ans,i - t);39 }40 printf(ans > 100000? "0\n":"%d\n",ans);41 }42 return 0;43 }
LA 2678 Subsequence(二分查找)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。