【尺取法】POJ3061&&POJ3320

Posted on 2018-05-14 19:22  som_nico  阅读(95)  评论(0编辑  收藏  举报

 

 

SubsequencePOJ3061

题意:

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

思路:

二分查找的话,前缀和是满足单调性的,计算从每一个数开始总和刚好大于s的长度。

具体实现就是:二分搜索s[i]+s是否存在于前缀和数组中,就是查找以i+1开头的总和刚好大于s的最短长度。

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e5+5;
int sum[maxn];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,S;
        cin>>n>>S;
        for(int i=0;i<n;i++)
        {
            int x;
            cin>>x;
            sum[i+1]=sum[i]+x;
        }
        if(sum[n]<S)
        {
            puts("0");
            continue;
        }
        int res=n;
        for(int s=0;sum[s]+S<=sum[n];s++)
        {
            int t=lower_bound(sum+s,sum+n,sum[s]+S)-sum;
            res=min(res,t-s);
        }
        cout<<res<<endl;
    }
    return 0;
}

 

尺取法:

常用的解题技巧:尺取法

 

 

Jessica's Reading ProblemPOJ3320

题意:看最小的页数,获得整本书的所有知识点。求这个页数是多少。(页数必须连续)

思路:所有知识点都被覆盖==每个知识点出现的次数都不小于1

   可以利用二叉树等数据结构来存储[s,t]区间上每个知识点的出现次数。

   从区间的最开头把s去除之后,s上书写的知识点的出现次数就要减一,如果此时这个知识点的出现次数为0,在同一个知识点再次出现前,不停将区间末尾t向后推进。

   时间:O(PlogP)

   ①用利用set集合里面元素的唯一性,将a[i]的所有元素放到里面去,这样就知道了一共有几个知识点。

   ②尺取法的原理是从起始left到末端right中寻找答案,然后利用map的映射,获得每个知识点所出现的数目即可。

   ③退出条件是sun < 知识点数目。

#include
#include
#include
#include
#include
using namespace std;

int p;
int a[1000000 + 10];

void solve(){
    set  ind;
    for (int i = 0; i < p; i++){
        ind.insert(a[i]);
    }
    int left = 0, right = 0, sum = 0;
    map  ans;
    int res = p;//假设全部都看一遍
    while (true){
        while (right < p && sum < ind.size()){
            //printf("ans[] = %d\n", ans[a[right]]);
            if (ans[a[right++]]++ == 0){
                sum++;
            }
        }
        //printf("sum = %d\n", sum);
        if (sum < ind.size()) break;
        res = min(res, right - left);
        if (--ans[a[left++]] == 0){//注意,这里不论if条件是否成立,--ans[a[left++]]的加减都会执行
            sum--;
        }
    } 
    printf("%d\n", res);
}

int main(){
    while(scanf("%d", &p) != EOF){
        memset(a, 0, sizeof(a));
        for (int i = 0; i < p; i++){
            scanf("%d", a + i);
        }
        solve();
    }
    return 0;
}