尺取法:
1.适用范围:顾名思义,像一把尺子一样量取目标,根据名字,能得到题目的一般适用范围为:连续,如果非连续估计就没什么用了。
2.好处:这样的方法能够减少大量冗余的枚举,极大优化时间,化腐朽(tle)为神奇(ac)。
3.方法:用一对下标保存左右端点,按题意移动左右端点即可。
下面是配套习题:
牛客网 Wannafly挑战赛23 A题 字符串
#include<bits/stdc++.h>
using namespace std;
map<char,int>vis;
string a;
int main()
{
cin>>a;
int sum=0;
int mlen=110;
int l=0;
for(int i=0;i<a.length();i++)
{
if(!vis[a[i]]){vis[a[i]]++;sum++;}
else vis[a[i]]++;
//cout<<sum<<endl;
while(sum==26)
{
int len=i-l+1;
if(mlen>len)mlen=len;
if(vis[a[l]]>1){vis[a[l]]--;l++;}
else {break;}
}
}
cout<<mlen<<endl;
return 0;
}
poj 3061 Subsequence
#include<bits/stdc++.h>
using namespace std;
map<char,int>vis;
int a[100005];
int main()
{
int t,n,sum=0,k,len;
cin>>t;
while(t--)
{
sum=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int mlen=110000;
for(int l=1,r=1;r<=n;r++)
{
sum+=a[r];
if(sum>=k)
{
while(sum>=k)
{
len=r-l+1;
mlen=min(len,mlen);
sum-=a[l];
l++;
}
}
}
printf("%d\n",mlen);
}
return 0;
}
poj 2739 Sum of Consecutive Prime Numbers
#include <bits/stdc++.h>
using namespace std;
const int N=1e4;
bool flag[N+10];
int prime[N+10];
int a[N];
int main()
{
memset(flag,1,sizeof(flag));//假设全是素数
flag[0]=0;flag[1]=0;//0和1不是素数
int index=0;
for(int i=2;i<=N;i++)
{
if(flag[i])prime[index++]=i;//得到素数集合
for(int j=0;j<index&&prime[j]*i<=N;j++)
{
flag[prime[j]*i]=0;//筛合数
if(i%prime[j]==0)break;//只筛合数的素因子最小的那一个
}
}
int n;
for(int i=2;i<=N;i++)
{
int sum=0;
int cnt=0;
int index=0;
for(int j=0;prime[j]<=i;j++)
{
sum+=prime[j];
if(sum<i)continue;
while(sum>i)
{
sum-=prime[index];
index++;
}
if(sum==i)cnt++;
}
a[i]=cnt;
}
while(~scanf("%d",&n)&&n)
{
printf("%d\n",a[n]);
}
return 0;
}
poj 2100 Graveyard Design
我英语是真的菜,还以为是设计什么花园,结果是墓地。。
这题数据一开始用我用int,结果疯狂tle,我就震惊了,刚学的尺取法都tle了,那我还做个屁,没想到看解题报告,是数据问题,以前爆int都是wa,这次居然是tle,长见识了。。
#include <bits/stdc++.h>
using namespace std;
int a[1020][3];
typedef long long ll;
struct node
{
ll l,ri,c;
}p[1020];
int main()
{
long long s;
scanf("%lld",&s);
long long sum=0;
ll index=1;
ll cnt=0;
for(long long i=1;i*i<=s;i++)
{
sum+=i*i;
if(sum<s)continue;
while(sum>s)//忘记这里是while了,检查了几遍
{
sum-=index*index;
index++;
}
if(sum==s)
{
p[cnt].c=i-index+1;
p[cnt].l=index;p[cnt].ri=i;
cnt++;
}
}
printf("%lld\n",cnt);
for(ll i=0;i<cnt;i++){
printf("%lld ",p[i].c);
for(ll k=p[i].l;k<=p[i].ri;k++)
printf("%lld ",k);
printf("\n");
}
return 0;
}
poj 3320 Jessica’s Reading Problem
这题被林大oj一顿爆坑,tle三回,我想这TM不可能爆int啊,就找了poj原题提交,结果516ms。。
#include <bits/stdc++.h>
using namespace std;
map<int,int>vis1,vis2;
int a[1000005];
int main()
{
int n;
scanf("%d",&n);
int sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(!vis1[a[i]])sum++;
vis1[a[i]]++;
}
int l=1,cnt=0;
int mlen=1000000;
int len;
for(int r=1;r<=n;r++)
{
if(!vis2[a[r]])cnt++;
vis2[a[r]]++;
while(cnt==sum&&l<=r)
{
len=r-l+1;
mlen=min(mlen,len);
if(vis2[a[l]]>1){vis2[a[l]]--;l++;}
else break;
}
}
printf("%d\n",mlen);
return 0;
}