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;
}
分类:
简单优化方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」