首页 > 其他分享 >尺取法

尺取法

时间:2023-07-27 23:45:22浏览次数:24  
标签:ch sum long 取法 include ll define

目录

尺取法

应用背景:
(1)给定一个序列,有时需要它是有序的,先排序
(2)问题和序列的区间有关,且需要操作两个变量,可以用两个下标(指针)i和j扫描区间

应用

寻找区间和

利用双指针寻找区间和
例题:

  1. Subsequence
    利用i和j标识滑动窗口的前后位置,因为当前ij段若大于s,则删头;若当前ij段小于s,则应继续加尾。
    例:
//>>>Qiansui
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
typedef std::pair<int,int> pii;
typedef std::pair<ll,ll> pll;
typedef std::pair<ull,ull> pull;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
	return x*f;
}

using namespace std;

const int maxm=1e5+5,inf=0x3f3f3f3f,mod=998244353;
ll n,s,a[maxm];

void solve(){
	cin>>n>>s;
	for(int i=1;i<=n;++i){
		cin>>a[i];
	}
	bool f=false;
	ll sum=a[1],ans=n+5;
	for(int i=1,j=1;i<=n&&j<=n;){
		if(sum>=s){
			if(ans>j-i+1){//统计答案
				ans=j-i+1;
				f=true;
			}
			sum-=a[i];
			++i;
			if(i>j){
				sum=a[i];
				++j;
			}
		}
		if(sum<s){
			++j;
			sum+=a[j];
		}
	}
	if(f) cout<<ans<<'\n';
	else cout<<0<<'\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}
  1. Bound Found
    与上面的题不同,这里需要利用前缀和转换一下,利用前缀和将滑动窗口显现出来,再利用尺取法找与题给的数字t差的绝对值最小的连续子序列
    摘记:古怪的编译器。。。还得了解了解poj的c++和g++的区别
//>>>Qiansui
//g++过的
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
// typedef pair<int,int> pii;
// typedef pair<ll,ll> pll;
// typedef pair<ull,ull> pull;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
	return x*f;
}

using namespace std;
const int maxm=1e5+5,inf=0x3f3f3f3f,mod=998244353;
ll n,k,a[maxm],t;
pair<ll,int> sum[maxm];

void solve(){
	while(1){
		cin>>n>>k;
		if(n==0) break;
		sum[0]=make_pair(0,0);
		for(int i=1;i<=n;++i){
			cin>>a[i];
			sum[i]=make_pair(sum[i-1].first+a[i],i);
		}
		sort(sum,sum+1+n);//注意从0开始,因为前缀和
		for(int z=0;z<k;++z){
			cin>>t;
			ll ans,l,r,cha=inf,ss;
			for(int i=0,j=1;j<=n&&i<=n;){
				ss=sum[j].first-sum[i].first;
				if(llabs(ss-t)<=cha){//找到一个更小的
					ans=ss;
					cha=llabs(ss-t);
					l=sum[i].second;
					r=sum[j].second;
				}
				if(ss>t) ++i;
				else if(ss<t) ++j;
				else break;
				if(i==j) ++j;
			}
			if(r<l) swap(l,r);//保证顺序,左在l,右在r
			cout<<ans<<' '<<l+1<<' '<<r<<'\n';//左区间需要加一
		}
	}
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
//	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

求包含多集合元素的最优解

2023杭电多校第四场 - 3 Simple Set Problem

标签:ch,sum,long,取法,include,ll,define
From: https://www.cnblogs.com/Qiansui/p/17586425.html

相关文章