1. 程式人生 > >Topcoder SRM 675 Div1 500Pts LimitedMemorySeries1(分塊)

Topcoder SRM 675 Div1 500Pts LimitedMemorySeries1(分塊)

tor bits fin get pre n) ted 多少 top

題意 給定一個長度不超過$5*10^{6}$的數列和不超過$100$個詢問,每次詢問這個數列第$k$小的數,返回所有詢問的和

   內存限制很小,小到不能存下這個數列。(數列以種子的形式給出)

   時限$10s$,內存限制$13MB$

我自己YY的分治縮小答案上下界範圍第三個樣例要跑$90s$左右,果斷放棄

根據題目給出的條件我們知道每一個數的範圍都在$[0, 10^{9}+6]$裏。

那麽我們開一個大小為$32000$的數組,把$[0, 10^{9}+6]$分成$32000$個大小相同的塊。

然後先遍歷整個數列,求出每個塊中有多少個數。

在詢問的時候先確定當前要查詢的那個數在哪個塊裏。

確定了那個塊的位置之後,我們再遍歷一遍數列,找到那些在這個塊裏的數,再把精確值求出來。

時間復雜度$O(qn)$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define MP		make_pair
#define fi		first
#define se		second

typedef long long LL;

const int N = 32000;

int block[N], c[N];

class LimitedMemorySeries1 {
	public:
		LL getSum(int n, int x0, int a, int b, vector<int> query){
			memset(block, 0, sizeof block);
			
			int x = x0;
			rep(i, 0, n - 1){
				block[x / N]++;
				x = (int)((x * (LL)a + b) % 1000000007);
			}

			LL sum = 0;
			for (auto q : query){
				int acum = 0;
				int p = -1;
				int before = 0;
				rep(i, 0, N - 1){
					if (acum <= q && q < acum + block[i]){
						p = i;
						before = acum;
						break;
					}
					acum += block[i];
				}

				memset(c, 0, sizeof c);

				x = x0;
				for (int i = 0; i < n; i++){
					if (p * N <= x && x < (p + 1) * N){
						c[x - p * N]++;
					}
					x = (int)((x * (LL)a + b) % 1000000007);
				}

				acum = before;
				int r = -1;
				for (int i = 0; i < N; i++){
					if (acum <= q && q < acum + c[i]){
                                                r = p * N + i;
                                                break;
                                        }
					acum += c[i];
				}
				sum += r;
			}

			return sum;
		}
};

  

Topcoder SRM 675 Div1 500Pts LimitedMemorySeries1(分塊)