A题: Task Computing
原题链接:https://ac.nowcoder.com/acm/contest/33189/A
题目大意
有
n
n
n 台云服务器,第
i
i
i 台具有计算效率
w
i
w_i
wi 和传输效率
p
i
p_i
pi 。
对于一个计算任务,需要恰好在
m
m
m 台服务器上计算,设这
m
m
m 台服务器依次为
a
1
,
a
2
,
.
.
.
,
a
m
a_1,a_2,...,a_m
a1,a2,...,am 则最终计算效率为
∑
i
=
1
m
w
a
i
∏
j
=
0
i
=
1
p
a
j
\sum\limits_{i=1}^mw_{a_i}\prod\limits_{j=0}^{i=1}p_{a_j}
i=1∑mwaij=0∏i=1paj
初始
a
0
=
0
,
p
0
=
1
a_0=0,p_0=1
a0=0,p0=1 。
求这
m
m
m 台服务器在最优排序下的最大计算效率。
题解
考虑在最优解中相邻的两台云服务器
a
k
,
a
k
+
1
a_k,a_{k+1}
ak,ak+1 ,设
a
k
=
x
,
a
k
+
1
=
y
a_k=x,a_{k+1}=y
ak=x,ak+1=y (即
w
a
k
=
w
x
,
p
a
k
+
1
=
p
y
w_{a_k}=w_x,p_{a_{k+1}}=p_y
wak=wx,pak+1=py )。
则显然此时的总贡献为
W
=
∑
i
=
1
k
−
1
w
a
i
∏
j
=
0
i
−
1
p
a
j
+
w
x
∏
j
=
0
k
−
1
p
a
j
+
w
y
p
x
∏
j
=
0
k
−
1
p
a
j
+
∑
i
=
k
+
2
m
w
a
i
∏
j
=
0
i
−
1
p
a
j
W=\sum\limits_{i=1}^{k-1}w_{a_i}\prod\limits_{j=0}^{i-1}p_{a_j}+w_x\prod\limits_{j=0}^{k-1}p_{a_j}+w_yp_x\prod\limits_{j=0}^{k-1}p_{a_j}+\sum\limits_{i=k+2}^mw_{a_i}\prod\limits_{j=0}^{i-1}p_{a_j}
W=i=1∑k−1waij=0∏i−1paj+wxj=0∏k−1paj+wypxj=0∏k−1paj+i=k+2∑mwaij=0∏i−1paj
(第三项中
w
y
p
x
∏
j
=
0
k
−
1
p
a
j
=
w
y
∏
j
=
0
k
p
a
j
w_yp_x\prod\limits_{j=0}^{k-1}p_{a_j}=w_ y\prod\limits_{j=0}^{k}p_{a_j}
wypxj=0∏k−1paj=wyj=0∏kpaj )
若我们交换这两台云服务器,即令
a
k
=
y
,
a
k
+
1
=
x
a_k=y,a_{k+1}=x
ak=y,ak+1=x 。
则显然此时的总贡献为
W
′
=
∑
i
=
1
k
−
1
w
a
i
∏
j
=
0
i
−
1
p
a
j
+
w
y
∏
j
=
0
k
−
1
p
a
j
+
w
x
p
y
∏
j
=
0
k
−
1
p
a
j
+
∑
i
=
k
+
2
m
w
a
i
∏
j
=
0
i
−
1
p
a
j
W'=\sum\limits_{i=1}^{k-1}w_{a_i}\prod\limits_{j=0}^{i-1}p_{a_j}+w_y\prod\limits_{j=0}^{k-1}p_{a_j}+w_xp_y\prod\limits_{j=0}^{k-1}p_{a_j}+\sum\limits_{i=k+2}^mw_{a_i}\prod\limits_{j=0}^{i-1}p_{a_j}
W′=i=1∑k−1waij=0∏i−1paj+wyj=0∏k−1paj+wxpyj=0∏k−1paj+i=k+2∑mwaij=0∏i−1paj
做差可得
W
−
W
′
=
(
w
x
∏
j
=
0
k
−
1
p
a
j
+
w
y
p
x
∏
j
=
0
k
−
1
p
a
j
)
−
(
w
y
∏
j
=
0
k
−
1
p
a
j
+
w
x
p
y
∏
j
=
0
k
−
1
p
a
j
)
=
∏
j
=
0
k
−
1
p
a
j
(
w
x
+
w
y
p
x
−
w
y
−
w
x
p
y
)
\begin{aligned} W-W'&=(w_x\prod\limits_{j=0}^{k-1}p_{a_j}+w_yp_x\prod\limits_{j=0}^{k-1}p_{a_j})-(w_y\prod\limits_{j=0}^{k-1}p_{a_j}+w_xp_y\prod\limits_{j=0}^{k-1}p_{a_j})\\ &=\prod\limits_{j=0}^{k-1}p_{a_j}(w_x+w_yp_x-w_y-w_xp_y) \end{aligned}
W−W′=(wxj=0∏k−1paj+wypxj=0∏k−1paj)−(wyj=0∏k−1paj+wxpyj=0∏k−1paj)=j=0∏k−1paj(wx+wypx−wy−wxpy)
因为在最优解中 a k = x , a k + 1 = y a_k=x,a_{k+1}=y ak=x,ak+1=y ,故 W − W ′ ≥ 0 W-W'\ge0 W−W′≥0 ,因为 ∏ j = 0 k − 1 p a j > 0 \prod\limits_{j=0}^{k-1}p_{a_j}>0 j=0∏k−1paj>0 , 所以可得 w x + w y p x − w y − w x p y ≥ 0 w_x+w_yp_x-w_y-w_xp_y\ge0 wx+wypx−wy−wxpy≥0 ,根据该公式进行排序后,最优解肯定为云服务器的一个子序列(因为排序后换位不可能使答案更优了)。
关于偏序性的证明
w x + w y p x − w y − w x p y ≥ 0 w x − w x p y ≥ w y − w y p x w x ( 1 − p y ) ≥ w y ( 1 − p x ) 1 − p y w y ≥ 1 − p x w x \begin{aligned} w_x+w_yp_x-w_y-w_xp_y&\ge0\\ w_x-w_xp_y&\ge w_y-w_yp_x\\ w_x(1-p_y)&\ge w_y(1-p_x)\\ \frac{1-p_y}{w_y}&\ge \frac{1-p_x}{w_x} \end{aligned} wx+wypx−wy−wxpywx−wxpywx(1−py)wy1−py≥0≥wy−wypx≥wy(1−px)≥wx1−px
该式左右两边分别只与 y , x y,x y,x 有关,显然具有传递性。
排序后,注意我们不能设状态 d p i , j dp_{i,j} dpi,j 表示前 i i i 台云服务器中选择 j j j 台的最优效率,然后大力 d p dp dp 。考虑到对于式 ∑ i = 1 m w a i ∏ j = 0 i = 1 p a j \sum\limits_{i=1}^mw_{a_i}\prod\limits_{j=0}^{i=1}p_{a_j} i=1∑mwaij=0∏i=1paj ,前面所选择的云服务器的 p p p 会对后面存在影响,因此存在后效性,不能直接 d p dp dp (同时我们也不能将 p p p 作为状态保存,复杂度不允许,而且浮点数也不方便保存)。
因此,我们设状态
d
p
i
,
j
dp_{i,j}
dpi,j 表示从第
i
i
i 到
n
n
n 台云服务器中选择
m
m
m 台的最优效率,此时后面所选择的云服务器不会对排在前面的云服务器造成影响,无后效性,可行。
易得转移式:
d
p
i
,
j
=
m
a
x
{
d
p
i
+
1
,
j
(
不选择第
i
台云服务器
)
d
p
i
+
1
,
j
−
1
∗
p
i
+
w
i
(
选择第
i
台云服务器
)
dp_{i,j}=max \begin{cases} dp_{i+1,j}&(不选择第i台云服务器)\\ dp_{i+1,j-1}*p_i+w_i&(选择第i台云服务器) \end{cases}
dpi,j=max{dpi+1,jdpi+1,j−1∗pi+wi(不选择第i台云服务器)(选择第i台云服务器)
最终答案即为 d p 1 , m dp_{1,m} dp1,m 。
参考代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T&x){//快读
char c,last=' ';
while(!isdigit(c=getchar()))last=c;
x=c^48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
if(last=='-')x=-x;
}
const int MAXN=1e5+5;
int n,m;
double dp[MAXN][25];
struct node{
int w;
double p;
}a[MAXN];
bool cmp(node a,node b){
return (1-a.p)/a.w<(1-b.p)/b.w;//注意sort时不允许有等号
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;++i)read(a[i].w);
for(int i=1;i<=n;++i)cin>>a[i].p,a[i].p/=10000;
sort(a+1,a+n+1,cmp);
double ans=0;
for(int i=n;i>=1;--i){
for(int j=1;j<=min(m,n-i+1);++j){
dp[i][j]=max(dp[i+1][j],dp[i+1][j-1]*a[i].p+a[i].w);
}
}
cout<<fixed<<setprecision(12)<<dp[1][m]<<'\n';
return 0;
}