【模拟8.07】柱形图(三分)
考试时没审清题,内存超限.......
事实上这是个三分题,
因为我们先假设一个最高点和最高点的高度,随着最高点高度的增加,
其他点的贡献为abs(a[j]-(h[i]-abs(i-j)))(j为最高点)
所以点的贡献的和是一个单峰函数(下凹的)
那么我们三分即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<string> 7 #include<map> 8 #include<vector> 9 #include<queue> 10 #include<set> 11 #define MAXN 200010 12 #define ps push_back 13 #define int long long 14 using namespace std; 15 int n;int a[MAXN];int max_r=0;int l,r;int minn=0x7ffffffffffff; 16 int work(int x,int root) 17 { 18 int sum=0; 19 for(int i=1;i<=n;++i) 20 { 21 int me=x-abs(i-root); 22 sum+=abs(a[i]-me); 23 } 24 minn=min(minn,sum); 25 return sum; 26 } 27 void three_divide(int x) 28 { 29 l=max(x,n-x+1);r=0x7ffffffffffff;;int mid; 30 while(l+2<r) 31 { 32 mid=l+(r-l)/3;int midd=r-(r-l)/3; 33 if(work(mid,x)>work(midd,x)) 34 { 35 l=mid; 36 } 37 else 38 r=midd; 39 //printf("l=%lld mid=%lld r=%lld\n",l,mid,r); 40 } 41 for(int i=l;i<=r;++i) 42 minn=min(minn,work(i,x)); 43 } 44 signed main() 45 { 46 scanf("%lld",&n); 47 for(int i=1;i<=n;++i) 48 { 49 scanf("%lld",&a[i]); 50 max_r=max(max_r,a[i]); 51 } 52 53 for(int i=1;i<=n;++i) 54 { 55 three_divide(i); 56 } 57 printf("%lld\n",minn); 58 }
至于正解
再次%%%%%skyh(用不是正解的方法碾压正解)
第一次听说模拟退火,很神奇的随机化算法(以后骗分的好技巧2333333),
然后就学了学,
定义了几个量
T初始化温度,esp最终温度,base变化倍数
nowpos,nowans现在位置和答案,lastpos,lastans
然后每次通过上一次位置随机化这一次的位置
之后改变ans时一种是lastans更优另一种是
(exp((lastans-nowans)/T)*RAND_MAX)>rand())
一种我不太会证的定理......总之就是以一定的概率即使不优也要转移
然后丑陋的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define MAXN 100010 3 #define ps push_back 4 #define int long long 5 using namespace std; 6 double esp=1e-5,T=1000,base=0.975; 7 int nowans,lastans; 8 int nowpos,lastpos; 9 int s[MAXN];int a[MAXN]; 10 int n; 11 int ans=0x7fffffffffff; 12 int find(int x) 13 { 14 int mid=(1+n)>>1; 15 for(int i=1;i<=n;++i)s[i]=a[i]+abs(x-i); 16 nth_element(s+1,s+mid,s+n+1); 17 int cal=s[mid]; 18 cal=max(cal,max(x,n-x+1)); 19 int tot=0; 20 for(int i=1;i<=n;++i)tot+=abs(cal-s[i]); 21 return tot; 22 } 23 signed main() 24 { 25 srand(time(0)); 26 scanf("%lld",&n); 27 for(int i=1;i<=n;++i) 28 { 29 scanf("%lld",&a[i]); 30 } 31 lastpos=(n+1)/2; 32 lastans=find(lastpos); 33 ans=min(ans,lastans); 34 while(T>esp) 35 { 36 nowpos=lastpos+(2ll*rand()-RAND_MAX)*T*0.000001; 37 if(nowpos<1) 38 { 39 nowpos=max(1ll,nowpos); 40 nowpos=min(n,nowpos); 41 } 42 else 43 { 44 nowpos=(nowpos%n+n-1)%n+1; 45 } 46 nowans=find(nowpos); 47 if(nowans<lastans||(exp((lastans-nowans)/T)*RAND_MAX)>rand()) 48 { 49 lastans=nowans; 50 lastpos=nowpos; 51 } 52 ans=min(ans,nowans); 53 T*=base; 54 } 55 printf("%lld\n",ans); 56 }