poj 2566 Bound Found 尺取法

题目链接

http://poj.org/problem?id=2566

 

思路

首先,从数据范围来看,这题只有用On或者Ologn的做法才不会超时

容易想到尺取法(时间复杂度On):

什么时候使用:

对于涉及到区间的问题,当固定区间一端时,另一端增加或减少使得答案发生单调性变化。

一些例子:

1.例如下标区间越大,ans越大,求大于given的子序列的最短长度。这时如果ans<given  r++,else l++,在On时间内可求得结果

2.当ans并不随下标的变化而单调性变化,例如本题,依然可以用尺取法解决这样的问题。

另外,如果对时间没有严格要求的话,能用尺取法一般也是能用二分的

 

具体分析

虽然下标区间的变化并不使ans单调改变,但是 这题求的不是子序列区间最短啊!就算是最长的也可以,只需要满足子序列的绝对值和t最接近就好了

所以我们转而分析子序列的绝对值——如果让它具有单调性就好解决了

由此引出正解:

先用一个结构体存前缀和和下标,让l和r对应值的区间,如果更小就更新答案,真正的区间端点用b[l].id,b[r].id更新

 

细节见代码(poj用结构体排序竟然会CE!!于是乎改用pair遂ac

code


//#include<bits/stdc++.h>  //使得差值最小   对区间长度并没有要求  这时需要重新排序 
#include<iostream>
#include<algorithm>
#define ll long long 
using namespace std;
int t,n,k,x;
int a[100005];
//struct node{
//	int pre;
//	int id;
//	bool operator < (const node &aa) const{
//		return pre<aa.pre;
//	}
//}b[100005];
typedef pair<ll, int> p;
p b[100005];

int main(){
	while(scanf("%d%d",&n,&k)==2&&!(n==0&&k==0)){
//		b[0]={0,0};
		b[0]=p(0,0);
//		for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]={a[i]+b[i-1].pre,i};
		for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=p(a[i]+b[i-1].first,i);
		sort(b,b+n+1);  //需要和0相比,因为有可能序列元素全是负数  r会一直走到n+1 不会得到答案 
		
		while(k--){
			scanf("%d",&x);
			
			int l=0,r=1,ans=2e9+10,mn=2e9+10,ansl,ansr;  
			while(r<=n){
//				int tem=b[r].pre-b[l].pre; 
				int tem=b[r].first-b[l].first; 
				if(abs(tem-x)<mn){
					mn=abs(tem-x);
					ans=abs(tem);
//					ansl=b[l].id,ansr=b[r].id;
					ansl=b[l].second,ansr=b[r].second;
				}
				
				if(tem>x){
					if(l<r) l++;
					else if(l==r) r++;
				}
 				else if(tem<x){
 					r++;
				}
				else break;
				if(l==r) r++;
				
			}
			if(ansl>ansr) swap(ansl,ansr);
			cout<<ans<<" "<<ansl+1<<" "<<ansr<<endl;
			
		}
	}
	return 0;
} 
posted @   starlightlmy  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示