一般是在给的一组数据中找到不大于某一个上限的“最优连续子序列”
给长度为n的数组和一个整数m,求总和不小于m的连续子序列的最小长度;
吃取法的基本思路是设置起始点与末尾点,然后末尾点不断自增直到满足一定条件,然后把该条件的一些情况记录,再把起始点自增,直到不满足条件,再自增末尾点,继续前面的,直到出界
1.延展尾点
2.退出条件
3.收缩前点
题
给出一个数组,求总和不小于m的连续子序列的最小长度
传送门
给出一个数组,求总和不小于m的连续子序列的最小长度
#include <iostream>
#include <cstdio>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=1e5+5;
int main(){
int t,s,n;
cin>>t;
int a[N];
while(t--){
cin>>n>>s;
for(int i=0;i<n;i++){scanf("%d",&a[i]);}
int st=0,en=0;//下标,st表示起始位置,en表示末尾位置
int ans=INF,sum=0;//ans表示答案,sum表示当前
while(1){
while(en<n&&sum<s)sum+=a[en++];
if(sum<s)break;//因为前面while语句使得一直满足sum>=s,直到整个式子都没有这个情况了就退出
ans=min(ans,en-st);//求取最短的子序列长度
sum-=a[st++];
}
if(ans==INF)ans=0;
printf("%d
",ans);
}
return 0;
}
一本书有p页,每页有一个知识点,求最少页数覆盖所有知识点
传送门
同上面一题,不同的是加了set求知识点的总数以及map求每个知识点的个数
然后相同的方法即可
/*
一本书有p页,每页有一个知识点,求最少页数覆盖所有知识点
*/
#include <iostream>
#include <cstdio>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e6+5;
int a[maxn];
std::map<int, int> cnt;
set<int> t;
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
t.insert(a[i]);
}
int num=t.size();//全部知识点
int en=0,st=0;//st表示开始下标,en表示结束下标
int sum=0;//目前学的知识点
int ans=INF;//求最短的
while(1){
while(en<n&&sum<num){//扩展右边
if(cnt[a[en++]]++==0)sum++;//没出现过的知识点进行记录,直到退出或者一段区间包含整个知识点
}
if(sum<num)break;//一般来说,从sum<num的循环中退出是不会执行这句,但从en<n退出表示都不满足条件了
ans=min(ans,en-st);//此时[st,en]必定是满足条件的
if(--cnt[a[st++]]==0)sum--;//缩短前面,如果在st后面还会出现的话,就缩短前面
}
printf("%d
",ans);
return 0;
}
/**
*set储存的是一串不重复的元素集合,且自动按照字典序进行排序
*insert()插入元素,size()获取元素个数,与map不同的是,map一对一地还存储了该元素的个数
*/
由连续素数相加为n的种类
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e4+5;
int prime[maxn];
int isprime[maxn];
int init(){
for(int i=0;i<maxn;i++)isprime[i]=i;
int k=0;
isprime[0]=isprime[1]=0;
for(int i=2;i<=maxn;i++){
if(isprime[i]){
prime[k++]=i;
for(int j=2*i;j<=maxn;j+=i){
isprime[j]=0;
}
}
}
return k;
}
int main(){
int cnt=init();
int n,k;
while(~scanf("%d",&n)){
if(n==0)break;
int st=0,en=0;
int sum=0;
int ans=0;
while(1){
while(en<cnt&&sum<n)sum+=prime[en++];
if(sum<n)break;
if(sum==n)ans++;
sum-=prime[st++];
}
printf("%d
",ans);
}
return 0;
}
平分和为n的情况
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#define ll long long
using namespace std;
struct node{
ll st,en;
};
vector<node> v;
int main(){
ll n;
while(~scanf("%lld",&n)){
v.clear();
ll st=1,en=1;
ll sum=0;
while(1){
while(en*en<=n&&sum<n){sum+=(en*en);en++;}
if(sum<n)break;
if(sum==n)v.push_back((node){st,en-1});
sum-=st*st;st++;
}
ll num=v.size();
printf("%lld
",num );
for(int i=0;i<num;i++){
printf("%lld",v[i].en-v[i].st+1);
for(ll k=v[i].st;k<=v[i].en;k++)printf(" %lld",k);
putchar('
');
}
}
return 0;
}