最近在做尺取法,总结一下
尺取法,说白了就是一个st,ed;这两个左右端点(起点、终点)在运动,适用条件就是要求一段连续的区间,
并且st(左端点)++的时候,一个更优的ed一定要大于或者等于原来的ed
所以尺取法是一种高效的枚举区间的方法,一般用于求取有一定限制的区间个数或最短的区间等等。
而且经常与map、set、multiset等连用
这里推荐几道题:
1、poj3061
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int main() { int n,S; int t; scanf("%d",&t); int a[100005]; while(t--) { scanf("%d %d",&n,&S); for(int i=0;i<n;i++){ scanf("%d",&a[i]); //printf("%d\n",sum[i+1]); } int res=n+1; int tr=0,s=0,sum=0; while(1) { while(tr<n&&sum<S) { sum+=a[tr++]; } if(sum<S)break; res=min(res,tr-s); sum-=a[s++]; } if(res>n)res=0; printf("%d\n",res); } }
poj3061
2、Codeforces Round #333 (Div. 2)
链接:http://codeforces.com/contest/602/problem/B
代码:
这道题结合了multiset
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; #define mod 1000000007 #define MAX 100005 int a[MAX]; int n; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; multiset<int>s; s.clear(); s.insert(a[1]); int Max=a[1],Min=a[1]; int st=1,ed=1; int ans=0; for(int i=2;i<=n;i++) { ed++; s.insert(a[i]); Max=max(Max,a[i]); Min=min(Min,a[i]); if(Max-Min<=1) ans=max((int)s.size(),ans); while(Max-Min>1&&s.size()>0) { multiset<int>::iterator it; it=s.find(a[st]); s.erase(it); st++; multiset<int>::iterator it1=--s.end(); multiset<int>::iterator it2=s.begin(); Max=*it1; Min=*it2; } } cout<<ans<<endl; return 0; }
尺取法
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; #define mod 1000000007 #define INF 0x3f3f3f3f #define MAX 100005 int Max[MAX],Min[MAX]; int n; int a[MAX]; int lowbit(int x) { return x&-x; } void updata(int i,int val) { while(i<=n){ Max[i]=max(Max[i],val); Min[i]=min(Min[i],val); i+=lowbit(i); } } bool query(int l,int r) { int maxn=a[l],minn=a[r]; while(1) { maxn=max(maxn,a[r]),minn=min(minn,a[r]); if(l==r) break; for(r-=1;r-l>=lowbit(r);r-=lowbit(r)) maxn=max(Max[r],maxn),minn=min(minn,Min[r]); } return maxn-minn<=1; } bool C(int l,int r) { return query(l,r); } int main() { memset(Min,INF,sizeof(Min)); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; updata(i,a[i]); } //cout<<query(1,2)<<endl; int ans=0; for (int i = 1; i <= n; i ++) { int l = i, r = n; while (l <= r) { int mid = (l + r)/2; if (C(i,mid)) l = mid+1; else r = mid-1; } //cout<<l<<r<<ans<<endl; ans = max(ans, r - i + 1); } cout<<ans<<endl; return 0; }
树状数组+二分
3、poj3320
原文地址:https://www.cnblogs.com/zhgyki/p/9568819.html
时间: 2024-09-30 23:58:03