Description
Input
Output
Sample Input
Sample Input1:
3 7 1 1 3 1
3 3 2
Sample Output1:
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
The Solution
搬来的。。
题目大意
每一轮有若干个正整数,每一轮会选出最大的一个(设其为 x)并将 x 用两个数取代之,一个是
⌊x∗p⌋
,一个是
x−⌊x∗p⌋
,
其中 p 为一个取值范围为(0,1)的实数,而其余的数都会加上一个非负整数 q。一开始有 n 个数,要进行 m 轮操作,问每轮操
作删掉的数和最后剩下的数。
f1 ≤ n ≤ 10
5
, 1 ≤ m ≤ 7 × 10
6
解题思路
先来考虑这样一个东西:
假设当前轮的数中最大为 x,y 为其余数中任意一个。
显然这一轮之后 x 会变成
⌊x∗p⌋
和
x−⌊x∗p⌋
,设 y 会在 k 轮之后被选出来,那么到时候 y 会变成
⌊y×p+k×q×p⌋
和
y−⌊y×p+k×q×p⌋
那么在之后的第 k 轮里,x 和 y 会变成⌊x × p⌋ + k × q,x + k × q − ⌊x × p⌋,⌊y × p + k × q × p⌋和 y − ⌊y × p + k × q × p⌋
考虑⌊x × p⌋ + k × q和⌊y × p + k × q × p⌋的大小关系:
将k × q放进下取整的式子里得到:⌊x × p + k × q⌋
又因为x ≥ y,p ∈ (0,1)
所以⌊x × p + k × q⌋ > ⌊y × p + k × q × p⌋
类似的,可以得到:x + k × q − ⌊x × p⌋ > y − ⌊y × p + k × q × p⌋
那么这个意味着什么?
我们将每一轮的所有数分成三类:
1、最开始的数
2、是由某一轮的最大值 x 得到的⌊x × p⌋
3、是由某一轮的最大值 x 得到的x − ⌊x × p⌋
那么开始的证明意味着第 2、3 种数中每次加入的数是不上升的。
于是我们得到这样一个算法:
对于每一种数我们维护一个单调的队列(三种就是说有 3 个队列),一开始只有第 1 种数有 n 个数,从大到小排序放进队列
里。
每一轮在三个队头中取出最大的(由于队列单调不上升,这个数必然是当前所有数中最大的),设其为 x,然后将 x 分成两个
数⌊x × p⌋,一个是x − ⌊x × p⌋,设 a=⌊x × p⌋,b= x − ⌊x × p⌋,将 a 放到第二个队列队尾,b 放到第三个队列队尾并将 x 从其
自己的队列中弹出。
对于每一轮其他数都加上 q 的操作可以通过记录某个数第一次出现的时间,即假设当前为第 i 轮,x 为这个数最开始的值,t
为出现时间,那么当前这个数为 x+(t-i)*q。
于是完美解决,空间复杂度 O(m)时间复杂度 O(m)
CODE
手打的 (被卡常了。。。改改数组大小。。。)
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 7000005
#define INF 2147483647
using namespace std;
typedef double db;
int n,m,q,u,v,t;
int b[3],c[3],g[3][N], d[3][N];
inline int read()
{
int x=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*w;
}
bool cmp(int x,int y)
{
return x > y;
}
int Calc(int i,int x)
{
if (b[i] > c[i]) return - INF;
return d[i][b[i]] + q * (x - g[i][b[i]] - 1);
}
int Pos(int x)
{
int wz = 0;
fo(i,0,2)
if (b[i] <= c[i]) if (Calc(i,x) > Calc(wz,x)) wz = i;
return wz;
}
int main()
{
freopen("earthworm.in","r",stdin);
freopen("earthworm.out","w",stdout);
n = read(),m = read(),q = read(),u = read(),v = read(),t = read();
fo(i,1,n) d[0][i] = read();
sort(d[0]+1,d[0]+1+n,cmp);
b[0] = b[1] = b[2] = 1;
c[0] = n;
fo(i,1,m)
{
int wz = Pos(i), len = Calc(wz,i);
if (i % t == 0) printf("%d ",len);
b[wz] ++;
d[1][++ c[1]] = int((u*1.0 / v * len));
d[2][++ c[2]] = len - int( u*1.0 / v * len);
g[1][c[1]] = i;
g[2][c[2]] = i;
}
printf("\n");
fo(i,1,n+m)
{
int wz = Pos(m + 1) , len = Calc(wz,m + 1);
if (i % t == 0) printf("%d ",len);
b[wz] ++;
}
return 0;
}