是不是我写错了(
原理是计算后一个数比前一个数小的个数,对该函数进行退火。
#include<iostream>
#include<random>
#include<ctime>
#include<cmath>
#define double long double
using namespace std;
int n,w,a[100001];
mt19937 mt(time(NULL));
int rd(int l,int r){
int add=mt()%(r-l+1);
return l+add;
}
int count(int x,int y){
int ans=0;
if(x>y)swap(x,y);
if(y==x+1){
if(a[x]>a[y])ans--;
if(a[x]<a[y])ans++;
if(x>1)ans-=a[x-1]>a[x];
if(y<n)ans-=a[y]>a[y+1];
if(x>1)ans+=a[x-1]>a[y];
if(y<n)ans+=a[x]>a[y+1];
}else{
if(x>1)ans-=a[x-1]>a[x];
if(x<n)ans-=a[x]>a[x+1];
if(y>1)ans-=a[y-1]>a[y];
if(y<n)ans-=a[y]>a[y+1];
if(x>1)ans+=a[x-1]>a[y];
if(x<n)ans+=a[y]>a[x+1];
if(y>1)ans+=a[y-1]>a[x];
if(y<n)ans+=a[x]>a[y+1];
}
return ans;
}
void SA(){
double temp=1e10;
while(temp>1e-8){
int s1=rd(1,n),s2=rd(1,n);
while(s1==s2)s2=rd(1,n);
int delta=count(s1,s2);
if(w+delta==0){
swap(a[s1],a[s2]);
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
exit(0);
}
if(delta<0){
swap(a[s1],a[s2]);
w+=delta;
}else{
if(exp(-delta/temp)*1e9>=rd(1,1e9)){
swap(a[s1],a[s2]);
w+=delta;
}
}
temp*=0.995;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=2;i<=n;i++){
w+=a[i-1]>a[i];
}
while(true)SA();
return 0;
}