题目链接: Bound Found
思路
用前缀和先统计每个数到第一个数的总和。因为尺取法需要数组有序,所以对前缀和得到的数组排序。设立两个类似指针了l,r,使得l,r不断前进,并记录这之间产生的最小值以及下标。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
int a[100001];
const int inf=0x3f3f3f3f;
struct node{
int value,id;
}sum[100001];
using namespace std;
bool com(node a,node b)
{
return a.value<b.value;
}
int main()
{
int n,t,k,miner,i,j,s,l,r,minerr,left,right;
ios::sync_with_stdio(0);
while(cin>>n>>k && n)
{
sum[0].value=0;
sum[0].id=0;
for(i=1;i<=n;i++)
{
cin>>a[i];
sum[i].value=sum[i-1].value+a[i];
sum[i].id=i;
}
sort(sum,sum+n+1,com);
for(i=1;i<=k;i++)
{
int l=0,r=1;
int miner=inf;
cin>>t;
while(l<=n && r<=n)
{
int ans=sum[r].value-sum[l].value;
if(abs(abs(ans)-t)<miner)
{
miner=abs(abs(ans)-t);
minerr=abs(ans);
left=min(sum[r].id,sum[l].id)+1;
right=max(sum[r].id,sum[l].id);
}
if(ans>t)
l++;
else if(ans<t)
r++;
else
break;
if(l==r) //如果在l或者r自加后有l==r,记得使r++,因为sum[r].value-sum[l].value不合法
r++;
}
cout<<minerr<<' '<<left<<' '<<right<<endl;
}
}
}
题目链接: Humble Numbers
思路
比赛的时候遇见的一个题,后来看解析时,感觉方法挺巧妙,有尺取法的味道,于是又做了一遍。我们的思路是任何一个丑数都是由某个合适的数*2或3或5或7,那么我们就需要不断的找这个合适的数,并始终把最小的值筛选出来,具体看代码。
#include <bits/stdc++.h>
using namespace std;
int a[5843];
void solve()
{
int i;
int b2,b3,b5,b7;
b2=b3=b5=b7=1;
a[1]=1;
for(i=2;i<=5842;i++)
{
a[i]=min(min(a[b2]*2,a[b3]*3),min(a[b5]*5,a[b7]*7));
if(a[i]==a[b2]*2)
b2++;
if(a[i]==a[b3]*3)
b3++;
if(a[i]==a[b5]*5),juti k
b5++;
if(a[i]==a[b7]*7)
b7++;
}
}
int main()
{
int n;
solve();
while(cin>>n && n)
{
if(n%10==1 && n%100!=11)
printf("The %dst humble number is %d.\n",n,a[n]);
else if(n%10==2 && n%100!=12)
printf("The %dnd humble number is %d.\n",n,a[n]);
else if(n%10==3 && n%100!=13)
printf("The %drd humble number is %d.\n",n,a[n]);
else
printf("The %dth humble number is %d.\n",n,a[n]);
}
}
题目链接: POJ-3320 Jessica’s Reading Problem
思路
以每个元素为子序列的头,开始往后找,直到使得子序列包含所有元素,但是我们不需要用两个嵌套的循环,而只是需要两个指针l,r,当我们从第一个元素开始往后找,直到找到相应的子序列,我们便记录这个子序列的长度,当我们再从第二个元素开始找的时候就不需要重新找了,因为以第二个元素为头的子序列的末位置一定大于以第一个元素开头的那个子序列的末位置,所以我们只需要从上一次标记的右端点那里再往后找就行。这就是两个指针l,r的好处,我们只需要不断挪动l,r即可。
#include <cstdio>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int a[1000001];
int main()
{
int n,i,num=0;
map<int,int>M;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(!M[a[i]])num++;
M[a[i]]++;
}
M.clear();
int l=1,r=1,sum=0,ans=inf;
while(1)
{
while(r<=n && sum<num)
{
if(!M[a[r]])
sum++;
M[a[r]]++;
r++;
}
if(sum<num) break;
ans=min(ans,r-l);
M[a[l]]--;
if(!M[a[l]])
sum--;
l++;
}
printf("%d\n",ans);
}
题目链接: POJ-3061 Subsequence
思路
和上一题一样的思想,都是以每一个元素都作为子序列的头位置,但是要记录下num,这样下一次就可以直接运用。
#include <cstdio>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int a[100001];
int main()
{
int t,i,n,k;
cin>>t;
while(t--)
{
cin>>n>>k;
for(i=1;i<=n;i++)
cin>>a[i];
int l=1,r=1,num=0,ans=inf;
while(1)
{
while(r<=n && num<k)
{
num+=a[r];
r++;
}
if(num<k) break;
ans=min(ans,r-l);
num=num-a[l++];
}
if(ans!=inf)
cout<<ans<<endl;
else
cout<<'0'<<endl;
}
}