zoukankan      html  css  js  c++  java
  • poj 3061(二分 or 尺取法)

    传送门: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
    ",res);
    45     }
    46 }
    二分
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 using namespace std;
     5 #define pb push
     6 const int maxn=1e5+50;
     7 
     8 int N,S;
     9 int a[maxn];
    10 queue<int >myqueue;
    11 
    12 int main()
    13 {
    14     int T;
    15     scanf("%d",&T);
    16     while(T--)
    17     {
    18         while(!myqueue.empty())
    19             myqueue.pop();
    20         scanf("%d%d",&N,&S);
    21         for(int i=1;i <= N;++i)
    22             scanf("%d",a+i);
    23         int end=1;
    24         int sum=0;
    25         int res=0;
    26         while(sum < S && end <= N)//先找到以1为序列起点的满足条件的最小的end
    27         {
    28             sum += a[end];
    29             res++;
    30             myqueue.pb(a[end++]);
    31         }
    32         if(sum >= S)
    33         {
    34             while(sum-myqueue.front() >= S)//找到满足条件的当前最小的范围
    35             {
    36                 sum -= myqueue.front();
    37                 myqueue.pop();
    38                 res--;
    39             }
    40             while(end <= N)
    41             {
    42                 myqueue.pb(a[end]);
    43                 sum += a[end++];
    44                 while(sum-myqueue.front() >= S)//步骤(2)
    45                 {
    46                     sum -= myqueue.front();
    47                     myqueue.pop();
    48                 }
    49                 res= res > myqueue.size() ? myqueue.size():res;//判断是否更新 res
    50             }
    51         }
    52         else
    53             res=0;
    54         printf("%d
    ",res);
    55     }
    56 }
    View Code
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 const int maxn=1e5+50;
     6 
     7 int N,S;
     8 int a[maxn];
     9 
    10 int Solve()
    11 {
    12     int start=1,end=1;
    13     int res=0;
    14     int sum=0;
    15     while(1)
    16     {
    17         while(end <= N && sum < S)
    18             sum += a[end++];
    19         if(sum < S)
    20             break;
    21         res=(res == 0 || (end-start) < res ? end-start:res);
    22         sum -= a[start++];
    23     }
    24     return res;
    25 }
    26 
    27 int main()
    28 {
    29     int T;
    30     scanf("%d",&T);
    31     while(T--)
    32     {
    33         scanf("%d%d",&N,&S);
    34         for(int i=1;i <= N;++i)
    35             scanf("%d",a+i);
    36         printf("%d
    ",Solve());
    37     }
    38 }
    尺取法&挑战程序设计竞赛
  • 相关阅读:
    给脚本绑定LUA解释器
    Flash Socket连接受限解决方法
    使用CMake构建编译环境
    如何使用OpenCL编写程序
    使用zzip和minizip解压缩文件
    使用CURL库下载文件
    使用GDI+保存位图文件为PNG文件
    linux学习
    Tomcat6连接池配置
    ArrayList与LinkedList性能差别
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9796354.html
Copyright © 2011-2022 走看看