Vjudge Bound Found 尺取法的好题

题目链接Bound Found
题意

有N个整数数,可负可正。给一个数t,然后从这N个数中找一个连续的区间,使得这个连续区间和的绝对值最接近t,求出这个连续区间和的绝对值和以及区间的上下界。

思路
  • 尺取法
    顾名思义,像尺子一样取一段,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。
  • 什么时候可以使用尺取法?
    我自己的理解是:答案在一段连续的区间内或者是一段连续的区间(可能有多个区间满足情况,题目要求你求出一个最优的区间),一般区间都是从数组的左端动态的移向右端。随着区间范围的扩大(右端点右移),就越靠近答案,区间缩小(左端点右移),就越远离答案。并且能够根据当前区间的状态判断是左端点或是右端点右移。
  • 例题




    像这样反复地推进区间的开头和末尾,来求取满足条件的最小区间的方法被称为尺取法。
  • 对于本题
    因为数组中的数有正有负,不能使用尺取法。为了可以使用尺取法,同时为了求出最优区间的上下界,可以先求出来前缀和,然后按照前缀和进行大小排序,排序的时候将前缀和以及下标使用结构体存储起来进行结构体排序。如果区间和sum<t,将右端点右移:如果sum>t,将左端点右移,这样保证sum尽可能的靠近t,区间在进行动态变换的时候更新答案即可
代码
//#pragma GCC optimize(2)
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;

typedef long long ll;
typedef unsigned long ul;
typedef unsigned long long ull;
#define pi acos(-1.0)
#define e exp(1.0)
#define pb push_back
#define mk make_pair
#define fir first
#define sec second                     
#define scf scanf
#define prf printf

typedef pair<int,int> pa;
const int INF=0x3f3f3f3f;
const int MAX_N=1e5+7;
int N,K,T;
int num[MAX_N];
struct node{
    
    
	int s,pos;
	bool operator<(const node &a)const{
    
    //从小到大排序 
		if(s!=a.s)
		return s<a.s;
		return pos<a.pos;
	}
};
vector<node>V;
void do_(int t){
    
    
	int L=0,R=1,aL,aR,minn=INF,sum=0,ans;
	while(L<=R&&R<V.size()){
    
    
		int sum=V[R].s-V[L].s;
		if(abs(sum-t)<minn){
    
    
			minn=abs(sum-t);
			ans=sum;
			aR=max(V[R].pos,V[L].pos);
			aL=min(V[R].pos,V[L].pos);
		}
		if(sum<t)
		R++;
		else if(sum>t)
		L++;
		else
		break;
		if(L==R){
    
    
			R++;
		}
	}
	prf("%d %d %d\n",ans,aL+1,aR);
}
int main()
{
    
    
//  freopen(".../.txt","w",stdout);
//  freopen(".../.txt","r",stdin);
//	ios::sync_with_stdio(false);
	int i,j,k;
	while(~scf("%d %d",&N,&K)&&(N||K)){
    
    
		V.clear();
		for(i=1;i<=N;i++){
    
    
			scf("%d",&num[i]);
		}
		int tmp=0;
		V.pb({
    
    0,0});
		for(i=1;i<=N;i++){
    
    
			tmp=tmp+num[i];
			V.pb({
    
    tmp,i});
		}
		sort(V.begin(),V.end());
		for(i=0;i<K;i++){
    
    
			scf("%d",&T);
			do_(T);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43311695/article/details/108629099