题意
给你
n
n
n,
k
k
k表示
n
n
n个人要出去玩,每辆车可以带
k
k
k个人,再给你
l
c
{l_c}
lc,
p
c
{p_c}
pc,
l
m
{l_m}
lm,
p
m
{p_m}
pm分别表示开车需要达到的年龄,买一辆车的花费,骑摩托需要达到的年龄,买一辆摩托的花费(摩托不能载人,也就是一辆摩托只能一个人骑着去)。
接下来给你
t
t
t,
d
d
d,表示
n
n
n个人之间可以互相转移年龄,每转移
1
1
1岁花费为
t
t
t,每个人最多转移
d
d
d岁(一个人的年龄不能低于
1
1
1岁),最后给你
n
n
n个人的年龄
a
i
{a_i}
ai。
也就是说,每个人可以选择开车,或者被开车的人带着,或者自己骑摩托出去,问你所有人出去玩的最小花费。如果无法所有人都出行,输出-1。
所有数据x均有 1 ⩽ x ⩽ 1 0 5 1\leqslant x\leqslant10^5 1⩽x⩽105
思路
1、刚开始看到
n
n
n这个范围以为是
d
p
dp
dp优化之类的东西,后来写了状态转移之后发现直接枚举开车的人的数量或者骑摩托的人的数量就行了,因为剩下的人的出行方式是确定的。
2、我们将每个人按照年龄从小到大排序,考虑贪心取年龄大的人开车,或者年龄大的人骑摩托。下面以贪心取年龄大的人开车为例:
①从小到大依次枚举开车出行的人数
c
r
cr
cr,则有最多
c
r
×
(
k
−
1
)
cr\times(k-1)
cr×(k−1) 个人可以被带,设为
g
z
gz
gz,剩下的
n
−
c
r
−
g
z
n-cr-gz
n−cr−gz 个人自己骑摩托出行,显然
g
z
gz
gz个被带着的优先取年龄小的人更优。因此需要判断的就是开车的和骑摩托的人是否能够借到足够的年龄。
②开两个数组分别表示从年龄大的开始开车能借出的年龄,和从年龄小的开始自己骑车能借到的年龄,再开一个数组表示从年龄小的开始被带着能借出多少年龄(注意每个人年龄至少
1
1
1岁,而且最多借
d
d
d岁)。
③从小到大枚举开车的人的人数,将需要借的总年龄加起来,能借出的总年龄加起来,判断是否足够借,足够的话就答案取最小值。
④注意特判没有人骑摩托的情况和某个人需要借超过
d
d
d岁的情况。贪心取年龄大的人骑摩托类似,留给读者自行思考。
⑤总时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),也就是排序的复杂度。
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3fLL
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dep(i,a,b) for(int i=(a);i>=(b);i--)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define fi first
#define se second
#define pb push_back
using namespace std;
const int maxn=4e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
ll n,m,k;
int a[maxn],c[maxn];
ll ans,tmp,cnt;
ll lc, pc, lm, pm;
ll t, d;
template <typename T>
inline void read(T &X){
X=0;int w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
if(w) X=-X;
}
ll mjie[maxn], cjie[maxn];//后缀能借的年龄(两种车)
ll totj[maxn];//前缀观众能借的年龄
ll myao[maxn],cyao[maxn];//前缀需要借的年龄(两种车)
void solve(){
read(n);
read(k);
read(lc);
read(pc);
read(lm);
read(pm);
read(t);
read(d);
ans = inf;
rep(i,1,n){
read(c[i]);
}
sort(c + 1, c + 1 + n);
cjie[n + 1] = 0;
mjie[n + 1] = 0;
dep(i,n,1) {
if(c[i]>=lm) {
mjie[i] = mjie[i + 1] + min(c[i] - lm, d);
}
else
mjie[i] = mjie[i + 1];
if(c[i]>=lc) {
cjie[i] = cjie[i + 1] + min(c[i] - lc, d);
}
else
cjie[i] = cjie[i + 1];
}
rep(i,1,n){
totj[i] = totj[i - 1] + min(d, 1LL * c[i] - 1);
if(c[i]+d<lm)
myao[i] = 0;
else if(c[i]<lm){
myao[i] = myao[i - 1] + lm - c[i];
}
else
myao[i] = myao[i - 1];
if(c[i]+d<lc)
cyao[i] = 0;
else if(c[i]<lc){
cyao[i] = cyao[i - 1] + lc - c[i];
}
else
cyao[i] = cyao[i - 1];
}
dep(i,n,1){
if(c[i]+d<lc)
break;
int cr = n - i + 1;//cr汽车数量
int gz = min(cr * (k - 1), n - cr);//gz观众数量(被开车的带着)
int mt = n - cr - gz;//mt骑摩托车的人的数量
ll kj = totj[gz] + cjie[n - cr + 1];//观众和开车的人能借到的年龄
ll xy = cyao[n] - cyao[n - cr];//开车的需要借的年龄
if(cr+gz>=n){//只有汽车和观众
if(kj>=xy)
ans = min(ans, cr * pc + xy * t);
continue;
}
if (c[gz + 1] + d < lm)
continue;
kj += mjie[gz + 1] - mjie[n - cr + 1];//骑摩托车的人能借的年龄
xy += myao[n - cr] - myao[gz];//骑摩托车的人需要借的年龄
if (kj >= xy)
ans = min(ans, pc * cr + pm * mt + xy * t);
}
//cout << "!!: " << ans << endl;
dep(i,n,1){
if(c[i]+d<lm)
break;
int mt = n - i + 1;
int cr = min(n - mt, (n - mt + k - 1) / k);
int gz = n - mt - cr;
ll kj = totj[gz] + mjie[n - mt + 1];
ll xy = myao[n] - myao[n - mt];
if(cr==0&&gz)//不合法情况
continue;
if(cr==0){//只有摩托车
if(kj>=xy)
ans = min(ans, mt * pm + xy * t);
continue;
}
if (c[gz + 1] + d < lc)
continue;
kj += cjie[gz + 1] - cjie[n - mt + 1];
xy += cyao[n - mt] - cyao[gz];
if (kj >= xy)
ans = min(ans, pc * cr + pm * mt + xy * t);
}
if(ans==inf)
ans = -1;
printf("%lld\n", ans);
}
int main(){
/*
#ifdef ONLINE_JUDGE
#else
freopen("D:/Temp/in.txt", "r", stdin);
#endif
*/
// freopen("e://duipai//myout.txt","w",stdout);
int T=1,cas=1;
//read(T);
while(T--){
solve();
}
//system("pause");
return 0;
}
/*
2 2
18 1000 16 1
5 3
16 15
2 2
23 10 15 5
2 2 9 20
*/