[***]HZOJ 柱状图
神仙题。
作者的正解:
算法二:对于60%的数据:考虑直接枚举屋顶的位置,总花费与屋顶的高度的关系是一个单峰函数,,我们可以用三分法三分屋顶的高度. 时间复杂度O(n2*logn)。
算法三:对于100%的数据: 我们枚举屋顶位置再三分高度的做法,复杂度的瓶颈在于花费的计算。假设屋顶在i处,高度为hi,如果j<i,有hj-j=hi-i ; 如果j>i,有hj+j=hi+i。
根据权值排序,建立树状数组来解决权值与i的权值的关系,用两个树状数组维护。时间复杂度O(n(logn)(logv),V为屋顶的高度。
对于60%的数据大概有两种做法:
1.如作者题解,说的挺清楚的。
2.考虑对于一个确定的位置作为屋顶,那么屋顶的高度是确定的,证明以后再说。将每个点的高度加上到屋顶的距离,高度为之后序列的中位数,所以就可以模拟退火了。
对于100%的数据:
1.模拟退火(没脸)。
2.枚举屋顶,三分高度,然后主要的优化就是在计算花费上。可以用两个树状数组维护。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #define int LL 6 #define LL long long 7 #define MAXN 100010 8 #define reg register 9 #define con const 10 using namespace std; 11 struct node 12 { 13 int val,id; 14 friend bool operator < (node a,node b) 15 {return !(a.val^b.val)?a.id<b.id:a.val<b.val;} 16 }al[MAXN],ar[MAXN]; 17 int n,a[MAXN],maxh,rkl[MAXN],rkr[MAXN]; 18 #define lowbit(x) ((x)&(-(x))) 19 struct bit 20 { 21 int C[MAXN],num[MAXN]; 22 void add(reg int x,reg con int y,reg con int z) 23 {while(x<=n){C[x]+=y;num[x]+=z;x+=lowbit(x);}} 24 pair<int,int> ask(reg int x) 25 { 26 int sum=0,nnum=0; 27 while(x) 28 { 29 sum+=C[x]; 30 nnum+=num[x]; 31 x-=lowbit(x); 32 } 33 return make_pair(sum,nnum); 34 } 35 }le,re; 36 __attribute((always_inline))int get(reg con int x,reg con int maxh) 37 { 38 int ans=0; 39 ans+=abs(maxh-a[x]); 40 int pos=upper_bound(al+1,al+n+1,(node){maxh-x,x})-al-1; 41 pair<int,int> tem=le.ask(pos); 42 ans+=tem.second*(maxh-x)-tem.first; 43 pair<int,int> tem2=le.ask(n); 44 ans+=tem2.first-tem.first-(tem2.second-tem.second)*(maxh-x); 45 pos=upper_bound(ar+1,ar+n+1,(node){maxh+x,x})-ar-1; 46 tem=re.ask(pos); 47 ans+=tem.second*(maxh+x)-tem.first; 48 tem2=re.ask(n); 49 ans+=tem2.first-tem.first-(tem2.second-tem.second)*(maxh+x); 50 return ans; 51 } 52 __attribute((always_inline))void read(int &s) 53 { 54 s=0; 55 reg int f=1;reg char a=getchar(); 56 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 57 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 58 s*=f; 59 } 60 signed main() 61 { 62 read(n); 63 int ans=0x7ffffffffffff; 64 for(reg int i=1;i<=n;++i) 65 { 66 read(a[i]); 67 al[i].val=a[i]-i,al[i].id=i; 68 ar[i].val=a[i]+i,ar[i].id=i; 69 } 70 sort(al+1,al+n+1); 71 sort(ar+1,ar+n+1); 72 for(reg int i=1;i<=n;++i)rkl[al[i].id]=i,rkr[ar[i].id]=i; 73 for(reg int i=1;i<=n;++i)re.add(rkr[i],a[i]+i,1); 74 for(reg int i=1;i<=n;++i) 75 { 76 re.add(rkr[i],-a[i]-i,-1); 77 int l=max(i,n-i+1),r=1e9,ml,mr; 78 ans=min(ans,get(i,l)); 79 while(r>l+1) 80 { 81 int mid=(l+r)>>1; 82 ml=mid-1,mr=mid; 83 int ans1=get(i,ml), 84 ans2=get(i,mr); 85 if(ans1<ans2)r=mid; 86 else l=mid; 87 ans=min(ans,ans1); 88 ans=min(ans,ans2); 89 if(!(ml^l)&&!(mr^r))break; 90 } 91 le.add(rkl[i],a[i]-i,1); 92 } 93 printf("%lld\n",ans); 94 }
波澜前,面不惊。