6638. 【GDOI2020.5.16模拟】Seat (队列)

Description:

https://gmoj.net/senior/#main/show/6638

题解:

因为数据太水了,所以暴力用map维护就能过这题了。

考虑一个更加靠谱的做法,类似于《蚯蚓》,用两个队列维护,一个队列是一开始的排好序加进去。

另一个队列就是新产生的数的队列。

不难发现,对于两个数\(x>y\),x产生的数一定大于等于y产生的数,所以第二条队列会一直是有序的。

每次从两个队列取出最大即可,注意最大有多个要全部去掉。

时间复杂度:\(O(n*log~V)\)

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 1e6 + 5;

int n;
ll a[N], A, B, C, mo;

int m;
struct nod {
	int i; ll x;
} b[N];

int ans[N];

int cmpb(nod a, nod b) {
	return a.x < b.x;
}

int cmpa(ll x, ll y) {
	return x > y;
}

struct P {
	int x; ll y;
	P(int _x = 0, ll _y = 0) {
		x = _x, y = _y;
	}
};

queue<P> d1, d2;

int main() {
	freopen("seat.in", "r", stdin);
	freopen("seat.out", "w", stdout);
	scanf("%d", &n);
	scanf("%lld %lld %lld %lld %lld", &a[1], &A, &B, &C, &mo);
	fo(i, 2, n) {
		a[i] = (a[i - 1] * a[i - 1] % mo * A + B * a[i - 1] + C) % mo + 1;
	}
	scanf("%d", &m);
	fo(i, 1, m) {
		scanf("%lld", &b[i].x);
		b[i].i = i;
	}
	sort(b + 1, b + m + 1, cmpb);
	sort(a + 1, a + n + 1, cmpa);
	fo(i, 1, n) d1.push(P(a[i], 1));
	ll sum = 0; int l = 0;
	while(d1.size() || d2.size()) {
		int x = 0;
		if(d1.size()) x = max(x, d1.front().x);
		if(d2.size()) x = max(x, d2.front().x);
		ll y = 0;
		while(d1.size() && d1.front().x == x) {
			y += d1.front().y;
			d1.pop();
		}
		while(d2.size() && d2.front().x == x) {
			y += d2.front().y;
			d2.pop();
		}
		
		if(x > 1) d2.push(P(x / 2, y));
		if(x > 2) d2.push(P((x - 1) / 2, y));
		
		sum += y;
		while(l < m && b[l + 1].x <= sum)
			l ++, ans[b[l].i] = x;
	}
	fo(i, 1, m) pp("%d\n", ans[i]);
}
posted @ 2020-05-16 16:02  Cold_Chair  阅读(260)  评论(0编辑  收藏  举报