• POJ 3061 (二分+前缀和or尺取法)


    题目链接http://poj.org/problem?id=3061

    题目大意:找到最短的序列长度,使得序列元素和大于S。

    解题思路

    两种思路。

    一种是二分+前缀和。复杂度O(nlogn)。有点慢。

    二分枚举序列长度,如果可行,向左找小的,否则向右找大的。

    前缀和预处理之后,可以O(1)内求和。

    #include "cstdio"
    #include "cstring"
    int sum[100005],n,s,a,T;
    bool check(int x)
    {
        int l,r;
        for(int i=1;i+x-1<=n;i++)
        {
            l=i,r=i+x-1;
            if(sum[r]-sum[l-1]>=s) return true;
        }
        return false;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&s);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a);
                sum[i]=sum[i-1]+a;
            }
            int l=0,r=n,ans=0;
            while(l<=r)
            {
                int mid=l+(r-l)/2;
                if(check(mid)) {ans=mid;r=mid-1;}
                else l=mid+1;
            }
            printf("%d
    ",ans);
            memset(sum,0,sizeof(sum));
        }
    }
    二分法

    另一种是某本著名的日译ACM书介绍的尺取法。复杂度O(n)

    这个方法很简单。

    ①令L=1,先找一下满足要求的第一个长度(当然不一定是最优结果)。期间R++不停伸展。

    ②满足了是吧,现在踢掉第一个元素,令L++。从第二个元素看起,不符合要求继续伸展R。更新一下ans。继续踢第二个元素。

    ③踢踢踢,直到不能伸展R,且不符合要求,break。

    这种方法只有一个疑问点,就是R不往回移动,其结果一定是对的吗?

    考虑一下,L一直向右移动,R其实没必要向左动了。R只有在不满足条件的时候才向右,否则停在原位。

    此时凭L的移动已经能找出所有可行的区间了。可以联想一下滑动变阻器,固定R,滑动L。

    #include "cstdio"
    #include "cstring"
    #include "iostream"
    using namespace std;
    int a[100005],n,s,l,r,T,sum,ans;
    int main()
    {
        //freopen("in.txt","r",stdin);
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&s);
            for(int i=1;i<=n;i++) scanf("%d",&a[i]);
            l=1,r=1,sum=0,ans=0x3f3f3f3f;
            while(true)
            {
                while(sum<s&&r<=n) sum+=a[r++];
                if(sum<s) break;
                ans=min(ans,r-l);
                sum-=a[l++];
            }
            if(ans==0x3f3f3f3f) printf("0
    ");
            else printf("%d
    ",ans);
        }
    }
    13592296 neopenx 3061 Accepted 548K 79MS C++ 593B 2014-11-02 20:53:32
  • 相关阅读:
    日志记录到txt文件
    使用NuGet安装EntityFramework4.2
    Redis 安装与简单示例 <第一篇>
    时间加减时间段(年、月、日、分、秒)
    控件属性设置
    window.showModalDialog 与window.open传递参数的不同?
    如何进行js动态生成option?如何实现二级连动?
    System.Data.SqlClient.SqlError: 备份集中的数据库备份与现有的 'XXX' 数据库不同
    如何激发手机的高分辨率
    PHP--正则表达式和样式匹配--小记
  • 原文地址:https://www.cnblogs.com/neopenx/p/4069841.html
Copyright © 2020-2023  润新知