目的:对给定的一个序列,在序列中寻找包含全部需求的、长度最小的一段子序列。一般用来解决具有单调性的区间问题。
时间复杂度:O(n)
https://blog.csdn.net/lxt_lucia/article/details/81091597
自用模板:
poj3061,给定一个序列,使得其和大于或等于S,求最短的子序列长度。
#include<stdio.h> #include<iostream> #define INF 0x3f3f3f3f using namespace std; const int maxn=1e5+10; int main() { int T; scanf("%d",&T); while(T--) { int n,s,a[maxn],st=0,en=0,ans=INF; long long sum=0; scanf("%d%d",&n,&s); for(int i=0;i<n;i++)scanf("%d",&a[i]); while(1) { while(en<n&&sum<s)sum+=a[en++]; if(sum<s)break; //如果右端点移动到区间末尾其和还不大于等于S,结束区间的枚举 ans=min(ans,en-st); sum-=a[st++]; } if(ans==INF)ans=0; printf("%d ",ans); } return 0; }
poj3320,一本书有P页,每一页都一个知识点,求去最少的连续页数覆盖所有的知识点,使用map来查询次数。
#include<stdio.h> #include<iostream> #include<map> #include<set> #define INF 0x3f3f3f3f using namespace std; const int maxn=1e6+10; map<int,int> mp; set<int> s; int main() { int n,a[maxn],st=0,en=0,ans=INF,num,sum=0; scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",&a[i]),s.insert(a[i]); num=s.size(); while(1) { while(en<n&&sum<num) { if(mp[a[en]]==0)sum++; mp[a[en]]++; en++; } if(sum<num)break; ans=min(ans,en-st); mp[a[st]]--; if(mp[a[st]]==0)sum--; st++; } if(ans==INF)ans=0; printf("%d ",ans); return 0; }
poj2739,找到某一个区间使得连续和等于某一给定值k。
#include<stdio.h> #include<iostream> #define INF 0x3f3f3f3f using namespace std; const int maxn=1e5+10; bool prime[maxn]; int p[maxn],tot; void init() { for(int i=2;i<10000;i++)prime[i]=true; for(int i=2;i<10000;i++) { if(prime[i])p[tot++]=i; for(int j=0;j<tot&&i*p[j]<10000;j++) { prime[i*p[j]]=false; if(i%p[j]==0)break; } } } int main() { init(); int n; while(scanf("%d",&n),n!=0) { int st=0,en=0,ans=0,sum=0; while(1) { while(en<n&&sum<n)sum+=p[en++]; if(sum==n)ans++; if(st==en)break; sum-=p[st++]; } printf("%d ",ans); } return 0; }
poj2100,找到某一个区间使得区间内的数的平方和等于某一给定值k。不加1LL的比较超时了(什么鬼哦),代码二的样式我jio的不错。
#include<stdio.h> #include<iostream> #define INF 0x3f3f3f3f using namespace std; const int maxn=1e5+10; struct node { int l,r; }p[maxn]; int main() { long long n; scanf("%lld",&n); int st=1,en=1,ans=0,k=0; long long sum=0; while(1) { while(1ll*en*en<=n&&sum<n)sum+=1ll*en*en,en++; if(sum==n)ans++,p[k].l=st,p[k++].r=en-1; if(sum<n)break; sum-=1ll*st*st,st++; } printf("%d ",ans); for(int i=0;i<k;i++) { printf("%d ",p[i].r-p[i].l+1); for(int j=p[i].l;j<p[i].r;j++) printf("%d ",j); printf("%d ",p[i].r); } return 0; }
#include<stdio.h> #include<iostream> #define INF 0x3f3f3f3f using namespace std; const int maxn=1e5+10; struct node { int l,r; }p[maxn]; int main() { long long n,sum=0,st=1,en=1; int ans=0,k=0; scanf("%lld",&n); while(1) { if(sum==n)ans++,p[k].l=st,p[k++].r=en-1; if(sum>=n)sum-=1ll*st*st,st++; else { if(en*en<=n)sum+=1ll*en*en,en++; else break; } } printf("%d ",ans); for(int i=0;i<k;i++) { printf("%lld ",p[i].r-p[i].l+1); for(long long j=p[i].l;j<p[i].r;j++) printf("%lld ",j); printf("%lld ",p[i].r); } return 0; }
uva 11572,求没有重复数字的最长区间。
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f const int maxn=1e6+10; int a[maxn]; int main() { int T; scanf("%d",&T); while(T--) { map<int,int> mp; int n,ans=1,st=0,en=0,sum=0; scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",&a[i]); while(1) { while(en<n) { if(mp[a[en]]==0)sum++,mp[a[en]]++,en++; else break; } ans=max(ans,en-st); if(en==n)break; if(mp[a[st]]==1)mp[a[st]]--; sum--; st++; } printf("%d ",ans); } return 0; }
atcoder 4142,求满足区间内al+al+1+al+2+...+ar==al^al+1^al+2^...^ar的区间个数
异或性质:a^b<=a+b,当且仅当a&b等于0时取等
#include<stdio.h> #include<iostream> using namespace std; const int maxn=2e5+10; long long a[maxn]; int main() { int n,en=0,st=0; long long sum=0,ans=0; scanf("%d",&n); for(int i=0;i<n;i++)scanf("%lld",&a[i]); while(1) { while(en<n) { if((sum&a[en])==0)sum+=a[en++],ans+=en-st; else break; } if(en==n)break; sum-=a[st++]; } printf("%lld ",ans); return 0; }
洛谷 p1102 a-b数对,这题直接map一下就好了,强行尺取要先来个sort排序,[枚举每个B+查询对应A]复杂度为O(n),sort完二分也可,尺取的优化在于B+C已经比最大的数大了,就break。
(*╹▽╹*)这题没有代码
poj2566,求一段子序列之和的绝对值最接近所给出的t,不能直接用尺取所以前缀+sort一哈,细节略多,试了很久。
#include<stdio.h> #include<iostream> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; const int maxn=1e5+10; int n,en,st,k,a[maxn],l,r,sum,ans,res,s; pair<int,int> pre[maxn]; int main() { while(scanf("%d%d",&n,&k)&&n!=0&&k!=0) { pre[0]=make_pair(0,0); for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i].first=pre[i-1].first+a[i],pre[i].second=i; sort(pre,pre+1+n); while(k--) { en=1,st=0,ans=INF,res=INF; //en=0会wa scanf("%d",&s); while(en<=n) { int tmp=pre[en].first-pre[st].first; if(abs(tmp-s)<=res) { res=abs(tmp-s); ans=abs(tmp); l=pre[st].second,r=pre[en].second; } if(tmp<s)en++; else if(tmp>s)st++; else break; if(en==st)en++; //这句没有会wa } if(l>r)swap(l,r); printf("%d %d %d ",ans,l+1,r); //前缀l和r之间包括了数l+1到r,所以刚开始要加pre[0] } } return 0; }
...over