233nmn
题目:题意:分析:代码:
题目:
传送门
题意:
给出
n
n
n个木材,各自的重量和下一个木材之间的距离 在最后一个位置设有木材厂,同时我们也可以自己设置两个木材厂在任意位置,所有木材只会向编号大的方向移动,直到第一个木材厂为止,花费为移动距离
∗
*
∗重量 问最少花费和是多少,在两个地方设木材厂能做到
分析:
模拟退火真是
x
s
w
l
xswl
xswl 首先分析下花费的求法,假设
a
,
b
a,b
a,b表示两个木材厂的位置,就有
=
∑
i
=
1
a
w
i
∗
∣
a
−
i
∣
+
∑
i
=
a
+
1
b
w
i
∗
∣
b
−
i
∣
+
∑
i
=
b
+
1
n
w
i
∗
∣
n
−
i
∣
=\sum_{i=1}^aw_i*|a-i|+\sum_{i=a+1}^bw_i*|b-i|+\sum_{i=b+1}^nw_i*|n-i|
=∑i=1awi∗∣a−i∣+∑i=a+1bwi∗∣b−i∣+∑i=b+1nwi∗∣n−i∣ 再设
d
i
d_i
di表示
1
∼
i
−
1
1\sim i-1
1∼i−1的距离,用下乘法分配律可以转换成这个亚子:
d
a
∗
∑
i
=
1
a
w
i
+
d
b
∗
∑
i
=
a
+
1
b
w
i
+
d
n
+
1
∗
∑
i
=
b
+
1
n
w
i
−
∑
i
=
1
n
w
i
∗
d
i
d_a*\sum_{i=1}^aw_i+d_b*\sum_{i=a+1}^bw_i+d_{n+1}*\sum_{i=b+1}^nw_i-\sum_{i=1}^nw_i*d_i
da∗i=1∑awi+db∗i=a+1∑bwi+dn+1∗i=b+1∑nwi−i=1∑nwi∗di 所有考虑把
w
w
w和
d
d
d用前缀和搞出来,而
a
,
b
a,b
a,b用模拟退火一位位移算下就
o
j
b
k
ojbk
ojbk了 比较特殊的是
t
l
a
s
t
t_{last}
tlast是无限趋近与
0.5
0.5
0.5的就够了,因为当
t
t
t在
0.5
0.5
0.5以下时对新的
a
,
b
a,b
a,b是不会有影响的,可以,但没必要
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<ctime>
#define LL long long
#define down 0.99
using namespace std
;
inline LL
read() {
LL d
=0,f
=1;char s
=getchar();
while(s
<'0'||s
>'9'){if(s
=='-')f
=-1;s
=getchar();}
while(s
>='0'&&s
<='9'){d
=d
*10+s
-'0';s
=getchar();}
return d
*f
;
}
LL n
=read();
LL w
[20005],d
[20005],s
;
struct qwq
{
LL a
,b
;
LL
get()
{
if(a
>b
) swap(a
,b
);
return w
[a
]*d
[a
]+(w
[b
]-w
[a
])*d
[b
]+(w
[n
]-w
[b
])*d
[n
+1]-s
;
}
}best
,now
,odd
;
void sa()
{
double t
=n
;
odd
.a
=rand()%n
+1; odd
.b
=rand()%n
+1;
while(t
>0.5)
{
int aa
=round((2.0*rand()/RAND_MAX
-1)*t
);
int bb
=round((2.0*rand()/RAND_MAX
-1)*t
);
now
.a
=(odd
.a
+aa
+n
)%n
+1;
now
.b
=(odd
.b
+bb
+n
)%n
+1;
LL dif
=now
.get()-odd
.get();
if(dif
<0) odd
=now
;
else if(exp(-dif
/t
)*RAND_MAX
>rand()) odd
=now
;
if(best
.get()>odd
.get()) best
=odd
;
t
*=down
;
}
return;
}
int main()
{
srand(19260817);
for(LL i
=1;i
<=n
;i
++)
{
LL a
=read(),b
=read();
w
[i
]=w
[i
-1]+a
;d
[i
+1]=d
[i
]+b
;
s
+=a
*d
[i
];
}
best
.a
=1;best
.b
=2;
for(int i
=1;i
<=233;i
++) sa();
cout
<<best
.get();
return 0;
}