传送门:Problem 3061

https://www.cnblogs.com/violet-acmer/p/9793209.html

 马上就要去上课了,先献上二分AC代码,其余的有空再补

题意:

  给定长度为 n 的整数数列 a[0,1,2,........,n]以及整数 S。

  求出总和不小于 S 的连续子序列的长度的最小值。

  如果解不存在,则输出 0。

题解:

  1、二分

    由于所有的元素都大于 0 ,所以数组a[ ] 的前缀和sum[ ]为递增的序列,满足二分的条件。

    首先确定子序列的起点为start(start的可能取值为 1,2,......,n)。

    假设区间[start,end]是以start为子序列起点的最小区间,则需要满足 sum[end]-sum[start-1] >= S,而确定满足条件的最小的 end 用二分即可在O(longn)的时间完成。

    所以总的时间复杂度为 O(nlogn)

  2、尺取法

    相关说明:

      设以a[start]为子序列起点的总和最初大于S的连续子序列为a[start,......,end],此时 res = end-start+1;

    (1):end++,找到最大的 k ,使得在去除当前子序列的前 k 个数后依旧满足 sum[end]-sum[start-1 + k] >= S,并判断是否需要更新 res。

    (2):重复(2)过程,直到 end > n 为止。

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define mem(a,b) (memset(a,b,sizeof(a)))
 6 const int maxn=1e5+50;
 7 
 8 int N,S;
 9 int a[maxn];
10 int sum[maxn];
11 int binarySearch(int val)
12 {
13     int l=0,r=N+1;
14     while(r-l > 1)
15     {
16         int mid=l+((r-l)>>1);
17         if(sum[mid] >= val)
18             r=mid;
19         else
20             l=mid;
21     }
22     return r;
23 }
24 int main()
25 {
26     int T;
27     scanf("%d",&T);
28     while(T--)
29     {
30         mem(sum,0);
31         scanf("%d%d",&N,&S);
32         int res=0;
33         for(int i=1;i <= N;++i)
34         {
35             scanf("%d",a+i);
36             sum[i] += sum[i-1]+a[i];
37         }
38         for(int s=1;s <= N;++s)
39         {
40             int t=binarySearch(sum[s-1]+S);
41             if(t != N+1)
42                 res=(res==0 || (t-s+1)<res ? t-s+1:res);
43         }
44         printf("%d\n",res);
45     }
46 }
二分

相关文章:

  • 2022-01-30
  • 2022-12-23
  • 2022-12-23
  • 2021-06-27
  • 2021-09-21
  • 2021-06-23
  • 2022-12-23
  • 2021-11-28
猜你喜欢
  • 2021-06-25
  • 2022-02-14
  • 2021-10-02
  • 2022-12-23
  • 2021-09-28
  • 2022-02-16
  • 2022-12-23
相关资源
相似解决方案