Bound Found(尺取)
阿新 • • 發佈:2018-12-19
思路來源
題意
給n個數,取部分連續和的絕對值,使之與給定的t儘可能接近。
輸出這部分和的絕對值,左下標和右下標。
心得
尺取需要排序維護單增的序列,
這樣才能大了推左端界使之更小,小了推右端界使之更大。
字首和也是可以排序的,由於是絕對值,所以不影響。
作差的時候取一下絕對值就可以,預存它們的位置。
下標從1到n還是有點好處,可以統一字首和p[r].sum-p[l].sum操作。
輸入時輸入p[1]-p[n],字首和維護,
這裡我們插入一個sum=0,pos=0的點p[0]參與排序。
這樣再後續處理時,l遇到這個點,
代表取前p[r].pos個數進行求和,此處用減0,這就統一了操作。
l==r是沒有意義的,一定要兩個不同的下標減否則沒有選中元素。
注意字首和作差,
[1,rpos]減[1,lpos]為(lpos,rpos],
故答案為[lpos+1,rpos]。
下標問題Debug很久啊真的很迷……
程式碼
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include <map> #include <vector> #include <stack> #include <queue> #include <functional> const int INF=0x3f3f3f3f; const int MAXN=1e5+10; const int mod=1e9+7; const int MOD=998244353; const double eps=1e-7; typedef long long ll; #define vi vector<int> #define si set<int> #define pii pair<int,int> #define pi acos(-1.0) #define pb push_back #define mp make_pair #define lowbit(x) (x&(-x)) #define sci(x) scanf("%d",&(x)) #define scll(x) scanf("%lld",&(x)) #define sclf(x) scanf("%lf",&(x)) #define pri(x) printf("%d",(x)) #define rep(i,j,k) for(int i=j;i<=k;++i) #define per(i,j,k) for(int i=j;i>=k;--i) #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; ll n,num,a[MAXN],k,l,r,lpos,rpos,ans,delta,mindelta; struct node { ll sum; ll pos; }p[MAXN]; bool operator<(node a,node b) { if(a.sum!=b.sum)return a.sum<b.sum; else return a.pos<b.pos; } void init() { l=0;r=1; mindelta=INF; } int main() { while(~scanf("%lld%lld",&n,&num)&&(n+num)) { rep(i,1,n) { scll(a[i]); if(i==1)p[i].sum=a[i]; else p[i].sum=p[i-1].sum+a[i]; p[i].pos=i; } p[0].sum=0,p[0].pos=0; sort(p,p+n+1);//單增字首和 才能尺取 保留下標故無影響 期間一個0也要考慮在內 rep(i,1,num) { init(); scll(k); while(r<=n&&mindelta)//為0肯定最符合要求,首先保證p[0].sum是無意義的0,1-n的下標優勢 { delta=p[r].sum-p[l].sum;if(delta<0)delta=-delta; ll tmp=delta-k;if(tmp<0)tmp=-tmp; if(tmp<mindelta)//如果更接近k { mindelta=tmp; ans=delta; lpos=p[l].pos; rpos=p[r].pos; } if(delta>k)l++; if(delta<k)r++; if(l==r)r++;//確保兩個不同的下標作差 } if(lpos>rpos)swap(lpos,rpos); printf("%lld %lld %lld\n",ans,lpos+1,rpos);//字首和作差[1,rpos]-[1,lpos]為(lpos,rpos],故為[lpos+1,rpos] } } return 0; }