尺取法题集合

尺取法入门题集:常用来解决区间有一定规律的题目。

  • 最小的区间满足和≥s
  • 最小的区间包含所有的种类
  • 多少区间的第k大的数≥m
  • 多少素数序列满足和等于n
  • 多少连续的数的平方和等于n

POJ3061

题意:最短的子串满足和≥s

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 1e5 + 10;
int const inf = 0x3f3f3f3f; //定义无穷大
int a[N],n,s;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int st = 1,sum = 0,ans = inf;
        for(int i=1;i<=n;i++){
            sum += a[i]; 
            while(sum >= s){
                ans = min(ans,i - st + 1);
                sum -= a[st++];
            }
        }
        if(ans == inf)    ans = 0;
        printf("%d\n",ans);
    }
    return 0;
}

HDU5806

题意:求有多少区间的第k大的数≥m。

题解:

  • 如果某个序列含有k个数大于等于m,那么可以保证加上后面的数,还是满足第k大的数≥m。
  • 采用尺取法,从头到尾扫描,每找到一段区间[l,r],满足有k个数大于等于m,那么区间[l,r...n]都是满足条件的,有n - r + 1种。

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 2e5 + 10;
int n,m,k,a[N];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
        int cnt = 0,st = 1;
        long long ans = 0;  //注意开long long
        for(int i=1;i<=n;i++){
            if(a[i] >= m)   cnt++;
            while(cnt == k){
                ans += (n - i + 1);
                if(a[st++] >= m)    cnt--;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

CF701C

题意:最短的子串包含字符串所有种类的字母。

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 1e5 + 10;
int const inf = 0x3f3f3f3f;
int n,num[250];
char s[N];
int main(){
    scanf("%d",&n);
    scanf(" %s",s);
    int k = 0;
    for(int i=0;i<n;i++)  //k表示字母总数
        if(++num[s[i]] == 1)    k++;
    memset(num,0,sizeof(num));
    int cnt = 0,st = 0;
    int ans = inf;
    for(int i=0;i<n;i++){
        if(++num[s[i]] == 1)    cnt++;
        while(cnt == k && st <= i){
            ans = min(ans,i - st + 1);
            if(--num[s[st]] == 0)    cnt--;
            st++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

POJ2739

题意:多少素数序列满足和等于n

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int const N = 10000;
int vis[N+10],prime[N+10],len;
void prime_table(){
    for(int i=2;i<N;i++){
        if(!vis[i]) prime[++len] = i;
        for(int j=1;j<=len&&prime[j]*i<N;j++){
            vis[prime[j]*i] = true;
            if(i % prime[j] == 0)   break;
        }
    }
}
int main(){
    prime_table();
    int n;
    while(~scanf("%d",&n) && n){    //n可以分解成多少个素数的和
        int ans = 0,sum = 0,st = 1;
        for(int i=1;i<=len;i++){
            sum += prime[i];
            while(sum >= n){
                if(sum == n)    ans++;
                sum -= prime[st++];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

POJ2100

题解:多少连续的数的平方和等于n

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
int const N = 100000 + 10;
ll n;
pii ans[N];
int main(){
    scanf("%lld",&n);
    ll sum = 0;
    int st = 1;
    int cnt = 0;
    for(int i=1;i<=1e7;i++){
        sum += 1ll*i * i;
        if(i * i > n) break;
        while(sum >= n){
            if(sum == n)    ans[++cnt] = pii(st,i);
            sum -= 1ll*st * st;
            st++;
        }
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++){
        printf("%d",ans[i].second - ans[i].first + 1);
        for(int j=ans[i].first;j<=ans[i].second;j++)  
            printf(" %d",j);
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值