[***]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 }
View Code

 

 

 

 

 

 

posted @ 2019-08-10 11:11  Al_Ca  阅读(137)  评论(0编辑  收藏  举报
ヾ(≧O≦)〃嗷~