http://poj.org/problem?id=3061
前缀和二分 复杂度O(nlogn)
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=100005;
int n,s,a[maxn],sum[maxn+1];
void solve(){
for(int i=0;i<n;i++){//计算前缀和
sum[i+1]=sum[i]+a[i];
}
if(sum[n]<s){
cout<<0<<endl;
return;
}
int res=n;
for(int i=0;sum[i]+s<=sum[n];i++){
int t=lower_bound(sum+i,sum+n,sum[i]+s)-sum;
res=min(res,t-i);
}
cout<<res<<endl;
}
int main(){
int N;
cin>>N;
while(N--){
cin>>n>>s;
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
for(int i=0;i<n;i++){
cin>>a[i];
}
solve();
}
return 0;
}
尺取法 复杂度O(n)
1.以s=t=sum=0初始化。
2.只要依然有sum<S,就不断将sum增加ai,并将t增加1。
3.如果2中无法满足sum>=S则终止。否则的话,更新res=min(res,t-s)。
4.将sum减去as,s增加1然后回到2.
像这样重复推进区间的开头和末尾,来求取满足条件的最小区间的方法被称为尺取法。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=100005;
int n,S,a[maxn];
void solve(){
int res=n+1;
int s=0,t=0,sum=0;
for(;;){
while(t<n&&sum<S){
sum+=a[t++];
}
if(sum<S) break;
res=min(res,t-s);
sum-=a[s++];
}
if(res>n){
res=0;
}
cout<<res<<endl;
}
int main(){
int N;
cin>>N;
while(N--){
cin>>n>>S;
for(int i=0;i<n;i++){
cin>>a[i];
}
solve();
}
return 0;
}