尺取法主要运用在,求某个序列的连续子序列满足大于或者小于t的最大长度等问题。(该序列要是所求意义上的单调序列)
poj3061
给定一个序列,找出最短的子序列长度,使得其和大于或等于S。
#include <iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1e5+10;
int a[maxn],Max;
void chiqu(int n,int s)
{
int i,j;
i=j=0;
int sum=0;
while(i<=j&&j<n)
{
if(sum+a[j]<s)
{
sum+=a[j];
j++;
}
if(sum+a[j]>=s)
{
sum-=a[i];
Max=min(Max,j-i+1);
i++;
}
}
}
int main()
{
int T,i,j,n,s;
scanf("%d",&T);
while(T--)
{
Max=1<<30;
scanf("%d %d",&n,&s);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
chiqu(n,s);
printf("%d\n",Max==1<<30?0:Max);
}
return 0;
}
poj3320
一本书有n页,每一页都一个知识点(用不同的数字表示,范围在int内),求去最少的连续页数覆盖所有的知识点。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
const int maxn=1e6+10;
const int INF=0x3f3f3f3f;
int a[maxn],Min,cunt;
map<int,int>vis;
void chiqu(int n)
{
int i,j;
i=j=0;
vis[a[0]]=1;
int ct=1;
while(i<=j&&j<n)
{
if(ct>=cunt)
{
Min=min(Min,j-i+1);
// printf("%d %d Min=%d\n",i+1,j+1,Min);
vis[a[i]]--;
if( !vis[a[i]])ct--;
i++;
}
else
{
j++;
if(!vis[a[j]])ct++;
vis[a[j]]++;
// printf("%d %d ct=%d\n",i+1,j+1,ct);
}
}
}
int main()
{
int n,i,j;
while(~scanf("%d",&n)&&n)
{
cunt=0;
Min=INF;
vis.clear();
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
if(!vis[a[i]]){vis[a[i]]=1;cunt++;}
}
// printf("cunt==%d\n",cunt);
vis.clear();
chiqu(n);
printf("%d\n",Min==INF?0:Min);
}
return 0;
}
poj2566
给出一个整数列,求一段子序列之和最接近所给出的t。输出该段子序列之和及左右端点。
这个没做出来。。。。贴个别人的代码 他的博客点击打开链接
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=1e5+5;
const int INF=2147483640;
pair<int,int> sum[MAXN];
int n,k,t;
void init()
{
sum[0]=make_pair(0,0);
int tmp=0;
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
tmp+=x;
sum[i]=make_pair(tmp,i);
}
sort(sum,sum+n+1);
}
void solve()
{
scanf("%d",&t);
int l=0,r=1,minans=INF,ans,ansl,ansr;
while (r<=n && minans)//这里一开始写成了ans,以后变量名不要取那么相像orz
{
int delta=sum[r].first-sum[l].first;
if (abs(delta-t)<=minans)
{
minans=abs(delta-t);
ans=delta;
ansl=sum[l].second;
ansr=sum[r].second;
}
if (delta<t) r++;
if (delta>t) l++;
if (l==r) r++;//☆注意序列不能为空!
}
if (ansl>ansr) swap(ansl,ansr);//注意排序后是无序的,左右区间要调整回有序
printf("%d %d %d\n",ans,ansl+1,ansr);
}
int main()
{
while (scanf("%d%d",&n,&k)!=EOF)
{
init();
for (int i=1;i<=k;i++) solve();
}
return 0;
}