写在前面的话:
这道题久违了
个人感觉这个题目的质量还是相当不错的,结合了队列和数学,难度上在Ac.Wing属于橙题范围,做这个题的时候发现的主要问题在于:
- 一些数学公式的推导思路和理解还要去训练
- 对于整体偏移和通过偏移量求值的问题的理解
下面给题解:
题解:
这个题目可以去用最朴素的方法解决:就是说我们定义一个偏移量,每一次从队列中取出一个最大值,然后把他分得的
f
l
o
o
r
(
p
x
)
floor(px)
floor(px)和
x
−
f
l
o
o
r
(
p
x
)
x - floor(px)
x−floor(px)全部减去q后加入集合中,然后每次我们要取他们的值,只需要加上整个集合的偏移量就可以了。这里可以理解为一种延迟叠加。但是这种方法复杂度太高,我们需要再优化。
下面开始数学推导:
假设现在集合中有
x
1
x_1
x1和
x
2
x_2
x2两种长度的蚯蚓,我们令
x
1
>
=
x
2
x_1 >= x_2
x1>=x2,现在将
x
1
x_1
x1取出,得到
f
l
o
o
r
(
p
x
1
)
,
x
1
−
f
l
o
o
r
(
p
x
1
)
floor(px_1),x_1 - floor(px_1)
floor(px1),x1−floor(px1),同时
x
2
−
>
x
2
+
q
x_2 -> x_2 + q
x2−>x2+q,现在我们假设
x
2
+
q
x_2 + q
x2+q被取出,那么分成
f
l
o
o
r
(
p
x
2
+
p
q
)
,
(
x
2
+
q
)
−
f
l
o
o
r
(
p
x
2
+
p
q
)
floor(px_2 + pq),(x_2 + q) - floor(px_2 + pq)
floor(px2+pq),(x2+q)−floor(px2+pq).
同时
x
1
x_1
x1也有了相应的变动:
f
l
o
o
r
(
p
x
1
)
+
q
,
x
1
+
q
−
f
l
o
o
r
(
p
x
1
)
floor(px_1) + q,x_1 + q - floor(px_1)
floor(px1)+q,x1+q−floor(px1)
我们可以得出:
f
l
o
o
r
(
p
x
1
)
+
q
=
f
l
o
o
r
(
p
x
1
+
q
)
>
=
f
l
o
o
r
(
p
x
1
+
p
q
)
>
=
f
l
o
o
r
(
p
x
2
+
p
q
)
floor(px_1) + q = floor(px_1 + q) >= floor(px_1 + pq) >= floor(px_2 + pq)
floor(px1)+q=floor(px1+q)>=floor(px1+pq)>=floor(px2+pq)
同时由于
(
x
1
−
x
2
)
>
=
p
(
x
1
−
x
2
)
,
x
1
−
p
x
1
>
=
x
2
−
p
x
2
(x_1 - x_2) >= p(x_1 - x_2),x_1 - px_1 >= x_2 - px_2
(x1−x2)>=p(x1−x2),x1−px1>=x2−px2
于是有
x
1
−
f
l
o
o
r
(
p
x
1
)
+
q
>
=
x
2
−
f
l
o
o
r
(
p
x
2
)
+
q
>
=
(
x
2
+
q
)
−
f
l
o
o
r
(
p
x
2
+
p
q
)
x_1 - floor(px_1) + q>= x_2 - floor(px_2) + q >= (x_2 + q) - floor(px_2 + pq)
x1−floor(px1)+q>=x2−floor(px2)+q>=(x2+q)−floor(px2+pq)
所以我们可以发现,对于先后取出的两个数,后取出的数新产生的两个数不可能比之前分得得数+q后大。这就意味着,我们可以直接在
f
l
o
o
r
(
p
x
)
floor(px)
floor(px),
x
−
f
l
o
o
r
(
p
x
)
x - floor(px)
x−floor(px),以及之前没有取过的数中取最大值就可以,可以采用三个队列存储数据。注意偏移量的设置!
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
#include<cstring>
#include<algorithm>
#define ll long long
#define INF 0x3f3f3f3f
#define inf -1e12
using namespace std;
queue<int > q1; //存floor(px)
queue<int > q2; //存x - floor(px)
priority_queue<int ,vector<int >,less<int > > q3; //存数组中剩下的
ll n,m,q,u,v,t;
ll calc(ll x)
{
ll a = inf,b = inf,c = inf,ans = 0;
if(!q1.empty()) a = q1.front() + x * q;
if(!q2.empty()) b = q2.front() + x * q;
if(!q3.empty()) c = q3.top() + x * q;
ans = max(a,max(b,c));
if(ans == a) q1.pop();
else if(ans == b) q2.pop();
else q3.pop();
return ans;
}
int main()
{
scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);
for(ll i = 1ll;i <= n;i++){
int x;
cin >> x;
q3.push(x);
}
for(ll i = 0ll;i < m;i++){
ll x = calc(i);
// cout << x << endl;
if((i + 1) % t == 0) printf("%lld ",x);
ll a1 = floor(x * u / v),a2 = x - floor(x * u / v);
q1.push(a1 - (i + 1) * q);
q2.push(a2 - (i + 1) * q);
}
printf("\n");
for(ll i = 1ll;i <= n + m;i++){
ll x = calc(m);
if(i % t == 0) printf("%lld ",x);
}
printf("\n");
return 0;
}