首页 > 代码库 > UER#7 T2
UER#7 T2
题意:给定n个数,对于2到n,分别输出一个答案。答案定义为:对于当前的数k,在原数组中找一个长度为k的区间,使得区间最值之差最小,输出差值。注意,差值允许5%的误差。
很少看见近似算法的题啊。。跪烂VFK大爷。
首先可以注意到的是,答案一定是单增的。我们再发现,随着1.05指数不断增加,之后肯定会有质的飞跃(毕竟是指数函数),也就是说,到时候一定有一大段区间的答案都是同一个数。所以我们只要分别找出每一个段的答案就好了。段数大概是log的(不会证,凭感觉吧。。。
先把2和n的答案计算出来,然后分治下去。如果当前分治的区间,左端点的答案误差范围已经和右边答案的误差范围相交,说明夹在他们中间的数们答案全一样,随便选一个复制给他们就好了。
时间复杂度O(nlogn)。跪烂。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define INF 1e9 5 #define eps 1e-5 6 inline int read(){ 7 int x=0,f=1; char a=getchar(); 8 while(a<‘0‘ || a>‘9‘) {if(a==‘-‘) f=-1; a=getchar();} 9 while(a>=‘0‘ && a<=‘9‘) x=x*10+a-‘0‘,a=getchar(); 10 return x*f; 11 } 12 int n,mx[N][20],mn[N][20],ans[N],Log[N]; 13 inline int Max(int x){ 14 return (int)((double)x*1.05+eps); 15 } 16 inline int Min(int x){ 17 return (int)((double)x*0.95+1-eps); 18 } 19 inline void pre(){ 20 Log[0]=-1; for(int i=1;i<=n;i++) Log[i]=Log[i>>1]+1; 21 for(int i=1;i<=18;i++) 22 for(int j=1;j<=n;j++){ 23 mx[j][i]=max(mx[j][i-1],mx[min(n,j+(1<<(i-1)))][i-1]); 24 mn[j][i]=min(mn[j][i-1],mn[min(n,j+(1<<(i-1)))][i-1]); 25 } 26 } 27 inline int qmx(int l,int r){ 28 return max(mx[l][Log[r-l+1]],mx[r-(1<<Log[r-l+1])+1][Log[r-l+1]]); 29 } 30 inline int qmn(int l,int r){ 31 return min(mn[l][Log[r-l+1]],mn[r-(1<<Log[r-l+1])+1][Log[r-l+1]]); 32 } 33 inline void cal(int x){ 34 ans[x]=INF; 35 for(int i=1;i<=n-x+1;i++) ans[x]=min(ans[x],qmx(i,i+x-1)-qmn(i,i+x-1)); 36 } 37 void dc(int l,int r){ 38 if(r-l<=1) return; 39 if(Max(ans[l])>=Min(ans[r])){ 40 int tmp=Max(ans[l]); 41 for(int i=l+1;i<r;i++) ans[i]=tmp; 42 return; 43 } 44 int mid=(l+r)>>1; 45 cal(mid); 46 dc(l,mid); dc(mid,r); 47 } 48 int main(){ 49 n=read(); for(int i=1;i<=n;i++) mx[i][0]=mn[i][0]=read(); 50 pre(); 51 cal(2); cal(n); dc(2,n); 52 for(int i=2;i<=n;i++) printf("%d\n",ans[i]); 53 return 0; 54 }
UER#7 T2
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。