[板子]模拟退火
1 #include<bits/stdc++.h> 2 #define N 100005 3 #define int long long 4 using namespace std; 5 const double eps=1e-5; 6 double delta=0.956,fj=1; 7 int n,ret,s[N],h[N]; 8 inline int _abs(int x){return x<0?-x:x;} 9 int calc(int pos,int height){ 10 int ans=0; 11 if(height<max(pos,n-pos))height=max(pos,n-pos); 12 for(int i=1;i<=n;++i)ans+=_abs(h[i]-_abs(height-_abs(i-pos))); 13 return ans; 14 } 15 int check(int pos){ 16 for(int j=1;j<=n;++j)s[j]=h[j]+_abs(pos-j); 17 int mid=1+n>>1; 18 nth_element(s+1,s+mid,s+n+1); 19 return calc(pos,s[mid]); 20 } 21 void simulate_annealing(){ 22 double T=1000; 23 int now=1+n>>1; 24 int tmpans=check(now); 25 while(T>eps){ 26 int u=now+(2ll*rand()-RAND_MAX)*T*0.00001; 27 if(T<fj)u=max(u,1ll),u=min(u,n); 28 else u=(u%n+n-1)%n+1; 29 int newans=check(u); 30 int D=newans-tmpans; 31 ret=min(ret,newans); 32 if(newans<tmpans||(double)exp(-D/T)*(double)RAND_MAX>(double)rand()) 33 tmpans=newans,now=u; 34 T*=delta; 35 } 36 } 37 signed main(){ 38 srand((unsigned)time(0)); 39 scanf("%lld",&n); 40 for(int i=1;i<=n;++i)scanf("%lld",&h[i]); 41 ret=0x7fffffffffffffff; 42 simulate_annealing(); 43 printf("%lld",ret); 44 }
Keep it simple and stupid.