尺取

尺取:顾名思义,就是拿一把尺子量取一段距离,然后就是不断的推进左右端点,进而将复杂度控制在O(n)范围内

下面我们可以做几道例题:
Subsequence
题意:就是找到长度最小的连续序列,加起来大于等于s。

这就是用到了尺取(很简单),下面是AC代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
#define int long long
int a[100010];
signed main()
{
    int t;
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> t;
    while (t--)
    {
        int n,s;
        cin >> n >>s;
        for (int i = 1; i <= n; i++) cin>>a[i];
        int cnt=0,sum=0,pos=1;
        int ans=1e18;
        for(int i=1;i<=n;i++)
        {
            while(sum<s&&cnt<n)
            {
                sum+=a[++cnt];
            }
            while(sum-a[cnt]>=s&&cnt>i)
            {                   
                sum-=a[cnt];
                cnt--;
            }
            if(sum>=s)
            {
                ans=min(ans,cnt-i+1);
            } 
            sum-=a[i];
        }
        if(ans<1e18) cout<<ans<<endl;
        else cout<<0<<endl;
    }
    
    return 0;
}

例题2:Jessica’s Reading Problem

题意:找到最小的区间能够包含数列中出现的所有的数
题解:也是很简单,就是注意一下本题的数据范围是爆int的
下面是AC代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <set>
    #include<map>
    using namespace std;
    #define int long long
    int a[1000100];
    map<int,int> num;
    signed main()
    {
        int t;
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        set<int> se;
        int n, s;
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> a[i],se.insert(a[i]);
        int len=se.size();
        int cnt=0,pos=0,ans=n;
        for (int i = 1; i <= n; i++)
        {
            while(pos<n&&cnt<len)
            {
                if(num[a[++pos]]==0)
                {
                    num[a[pos]]++;
                    cnt++;
                }
                else num[a[pos]]++;
            }
            while(cnt==len&&pos>i)
            {
                if(num[a[pos]]>1)
                {
                    num[a[pos]]--;
                    pos--;
                }
                else break;
            }
            if(cnt==len) ans = min(ans, pos - i + 1);
            num[a[i]]--;
            if(num[a[i]]==0) cnt--;
        }
        cout << ans << endl;
        return 0;
    }

例题3:
Bound Found
这个题就是找到区间和与给定的数最接近的区间,但是改了很长时间也没有改对,网上的代码也是错的,但是思想是正确的。

就是这个题因为是让求绝对值,所以我们可以用前缀和的思想,因为两个前缀和之差就是一段区间内的和,我们将其从小到达排序,这样就能保证他的单调性。单调性是前缀和排序后最优的性质,所以我们这样就可以运用一般的尺取方法从前往后维护>x的第一个值,和<x的最后一个值,或者是=x那个值。下面是半成品代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define int long long
const int N=100010;
struct node
{
    int v;
    int p;
}a[N];
bool cmp(const node &w1,const node &w2)
{
    return w1.v<w2.v;
}
signed main()
{
     int n,m;
     while(cin>>n>>m,n+m)
     {
        for(int i=1;i<=n;i++) 
        {
            int x;
            cin>>x;
            a[i].p=i;
            a[i].v=a[i-1].v+x;
        }
        sort(a+1,a+1+n,cmp);
        while(m--)
        {
            int x;
            cin>>x;
            int pos=1;
            int ansl,ansr,len=0x3f3f3f3f;
            for(int i=1;i<=n;i++)
            {
                pos=max(pos,i);
                while(a[pos].v-a[i-1].v<x&&pos<n)//维护到第一个大于他的值或等于的值
                {
                    if(abs(len-x)>abs(a[pos].v-a[i-1].v-x))
                    {
                        len=abs(a[pos].v-a[i-1].v);
                        ansl=a[i-1].p+1,ansr=a[pos].p;
                    }
                    pos++;
                }
                if(a[pos].v-a[i-1].v==x)
                {
                    len=x;
                    ansl=a[pos].p,ansr=a[i-1].p+1;
                    //break;
                }
                if(a[pos].v-a[i-1].v>x)
                {
                    if(abs(len-x)>abs(a[pos].v-a[i-1].v-x))
                    {
                        len=a[pos].v-a[i-1].v;
                        ansl=a[i-1].p+1,ansr=a[pos].p;
                    }
                    pos--;
                }
            }
            if(ansl>ansr) swap(ansl,ansr);
            cout<<len<<" "<<ansl<<" "<<ansr<<endl;
        }
     }
     return 0;
}

例题4:Graveyard Design
题意:就是求某个数是多少个连续的数的平方和,并将所有的情况求出来。一般尺取,注意下标即可,下面是AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
#define int long long
const int N=1e7+10;
vector<pair<int,int> > vec;
signed main()
{
    int x;
    cin>>x;
    int pos=1;
    int sum=0;
    int up=sqrt(x);
    for(int i=1;i<=up;i++)
    {
        while(sum+pos*pos<x&&pos<up)
        {
            sum+=pos*pos;
            pos++;
        }
        if(sum+pos*pos==x)
        {
            pair<int,int> pii;
            pii.first=i;
            pii.second=pos;
            vec.push_back(pii);
        }
        sum-=i*i;
    }
    cout<<vec.size()<<endl;
    for(int i=0;i<vec.size();i++)
    {
        int x=vec[i].first;
        int y=vec[i].second;
        cout<<y-x+1;
        for(int j=x;j<=y;j++)
        {
            cout<<" "<<j;
        }
        cout<<endl;
    }
    return 0;
}

例题5:Sum of Consecutive Prime Numbers
题意:就是找出一个数字可以用x个连续数表达的形式的个数。
题解:先把所有的质数筛出来,然后就是按照普通的来就行了。
下面是AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e5+10;
bool st[N];
int prime[N],cnt;
void is_prime(int n)
{
    int i,j;
    for(i=2;i<=n;i++)
    {
        if(!st[i]) prime[++cnt]=i;
        for(j=1;j<=cnt&&prime[j]<=n/i;j++)
        {
            st[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int n;
    is_prime(10010);
    while(cin>>n,n)
    {
        int pos=1;
        int ans=0;
        int sum=0;
        for(int i=1;i<=cnt;i++)
        {
            while(sum+prime[pos]<n&&pos<cnt)
            {
                sum+=prime[pos];
                pos++;
            }
            if(sum+prime[pos]==n)
            {
                ans++;
            }
            sum-=prime[i];
        }
        cout<<ans<<endl;
    }
}

例题6:戳我
例题6的题目和题解都在上面了,是一道尺取+二分的题目

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值