尺取法总结

最近在做尺取法,总结一下

尺取法,说白了就是一个st,ed;这两个左右端点(起点、终点)在运动,适用条件就是要求一段连续的区间,

并且st(左端点)++的时候,一个更优的ed一定要大于或者等于原来的ed

所以尺取法是一种高效的枚举区间的方法,一般用于求取有一定限制的区间个数或最短的区间等等。

而且经常与map、set、multiset等连用

这里推荐几道题:

1、poj3061

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
    int n,S;
    int t;
    scanf("%d",&t);
    int a[100005];
    while(t--)
    {
        scanf("%d %d",&n,&S);
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
         //printf("%d\n",sum[i+1]);
        }

        int res=n+1;
        int tr=0,s=0,sum=0;
      while(1)
       {
           while(tr<n&&sum<S)
           {
               sum+=a[tr++];
           }
           if(sum<S)break;
          res=min(res,tr-s);
          sum-=a[s++];
       }
       if(res>n)res=0;
       printf("%d\n",res);
    }
}

poj3061

2、Codeforces Round #333 (Div. 2)

链接:http://codeforces.com/contest/602/problem/B

代码:

这道题结合了multiset

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mod 1000000007
#define MAX 100005
int a[MAX];
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    multiset<int>s;
    s.clear();
    s.insert(a[1]);
    int Max=a[1],Min=a[1];
    int st=1,ed=1;
    int ans=0;
    for(int i=2;i<=n;i++)
    {
        ed++;
        s.insert(a[i]);
        Max=max(Max,a[i]);
        Min=min(Min,a[i]);
        if(Max-Min<=1)
        ans=max((int)s.size(),ans);
        while(Max-Min>1&&s.size()>0)
        {
            multiset<int>::iterator it;
            it=s.find(a[st]);
            s.erase(it);
            st++;
            multiset<int>::iterator it1=--s.end();
            multiset<int>::iterator it2=s.begin();
            Max=*it1;
            Min=*it2;
        }
    }
    cout<<ans<<endl;
    return 0;
}

尺取法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mod 1000000007
#define INF 0x3f3f3f3f
#define MAX 100005
int Max[MAX],Min[MAX];
int n;
int a[MAX];
int lowbit(int x)
{
    return x&-x;
}
void updata(int i,int val)
{
    while(i<=n){
    Max[i]=max(Max[i],val);
    Min[i]=min(Min[i],val);
    i+=lowbit(i);
    }
}
bool query(int l,int r)
{
    int maxn=a[l],minn=a[r];
    while(1)
    {
        maxn=max(maxn,a[r]),minn=min(minn,a[r]);
        if(l==r) break;
        for(r-=1;r-l>=lowbit(r);r-=lowbit(r))
            maxn=max(Max[r],maxn),minn=min(minn,Min[r]);
    }
    return maxn-minn<=1;
}
bool C(int l,int r)
{
    return query(l,r);
}
int main()
{
    memset(Min,INF,sizeof(Min));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
      updata(i,a[i]);
   }
   //cout<<query(1,2)<<endl;
    int ans=0;
   for (int i = 1; i <= n; i ++)
    {
        int l = i, r = n;
        while (l <= r)
        {
            int mid = (l + r)/2;
            if (C(i,mid)) l = mid+1;
            else r = mid-1;
        }
        //cout<<l<<r<<ans<<endl;
        ans = max(ans, r - i + 1);
   }
   cout<<ans<<endl;
    return 0;
}

树状数组+二分

3、poj3320

原文地址:https://www.cnblogs.com/zhgyki/p/9568819.html

时间: 2024-08-01 08:19:52

尺取法总结的相关文章

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间

poj 3320 Jessica&#39;s Reading Problem(尺取法+map/hash)

题目:http://poj.org/problem?id=3320 题意:给定N个元素的数组,找出最短的一段区间使得区间里面的元素种类等于整个数组的元素种类. 分析:暴力枚举区间的起点x,然后找到最小的y,使得区间[x,y]满足条件,x向有移位后变成x',现在的y'肯定不至于在y的左边.存状态的话map和hash都可以. map代码: #include <iostream> #include <set> #include <map> #include <cstdi

hihocoder-1483区间价值 (二分+尺取法)

题目链接: 区间价值 给定n个数A1...An,小Ho想了解AL..AR中有多少对元素值相同.小Ho把这个数目定义为区间[L,R]的价值,用v[L,R]表示. 例如1 1 1 2 2这五个数所组成的区间的价值为4. 现在小Ho想知道在所有的的v[L,R](1 <= L <= R <= n)中,第k小的值是多少. Input 第一行一个数T(T<=10),表示数据组数. 对于每一组数据: 第一行两个数n,k(1<=n<=200,000,1<=k<=n*(n+1

【转】毛虫算法&mdash;&mdash;尺取法

转自http://www.myexception.cn/program/1839999.html 妹子满分~~~~ 毛毛虫算法--尺取法 有这么一类问题,需要在给的一组数据中找到不大于某一个上限的"最优连续子序列" 于是就有了这样一种方法,找这个子序列的过程很像毛毛虫爬行方式,我管它叫毛毛虫算法,比较流行的叫法是"尺取法". 喏,就像图里的妹纸一样~ 还是举个栗子: Poj3061 给长度为n的数组和一个整数m,求总和不小于m的连续子序列的最小长度 输入 n = 1

51nod1127(尺取法)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1127 题意:中文题诶- 思路:尺取法 维护一个队列,若当前队首的元素在后面出现了,那么我们就将其删除,若当前队列里含有26个字母,我们就记录其size. 取所有size里面的最小值就是我们要的答案... 代码: 1 #include <iostream> 2 #include <stdio.h> 3 #include <string>

BestCoder Round #86 二,三题题解(尺取法)

第一题太水,跳过了. NanoApe Loves Sequence题目描述:退役狗 NanoApe 滚回去学文化课啦! 在数学课上,NanoApe 心痒痒又玩起了数列.他在纸上随便写了一个长度为 nnn 的数列,他又根据心情随便删了一个数,这样他得到了一个新的数列,然后他计算出了所有相邻两数的差的绝对值的最大值. 他当然知道这个最大值会随着他删了的数改变而改变,所以他想知道假如全部数被删除的概率是相等的话,差的绝对值的最大值的期望是多少. 输入描述 第一行为一个正整数 T,表示数据组数. 每组数

POJ 3320 尺取法,Hash,map标记

1.POJ 3320 2.链接:http://poj.org/problem?id=3320 3.总结:尺取法,Hash,map标记 看书复习,p页书,一页有一个知识点,连续看求最少多少页看完所有知识点 必须说,STL够屌.. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio>

HDU 5672 String 尺取法追赶法

String Problem Description There is a string S.S only contain lower case English character.(10≤length(S)≤1,000,000)How many substrings there are that contain at least k(1≤k≤26) distinct characters? Input There are multiple test cases. The first line

hdu-5672 String(尺取法)

题目链接: String Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 有一个 10\leq10≤长度\leq 1,000,000≤1,000,000 的字符串,仅由小写字母构成.求有多少个子串,包含有至少k(1 \leq k \leq 26)k(1≤k≤26)个不同的字母? 输入描述 输入包含多组数据. 第一行有一个整数T (1\leq T\leq 10)T(1≤T≤1

poj 3320 Jessica&#39;s Reading Problem (尺取法)

Jessica's Reading Problem Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8787   Accepted: 2824 Description Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent littl