XVII Open Cup named after E.V. Pankratiev
Grand Prix of Moscow Workshops, Sunday, April 23, 2017
Problem I. Rage Minimum Query
Input file: standard input
Output file: standard output
Time limit: 5 seconds
Memory limit: 512 mebibytes
Gleb proposed a problem for the contest:
Given an array of n integers, where n is up to 107, answer queries of kind “change i-th element to x” and
report the global minimum after each query.
Gleb is a very experienced problemsetter. He knows that random tests check everything and there is no
need to add any other. However, the contest is held tomorrow, and even random tests require some time
to prepare them. That’s why he asked you to generate tests by yourself.
You are given a linear pseudo-random generator specified by integers x0, x1, a, b and c. Here is the code
of a procedure which yields random integers in C++:
uint32_t next() {
uint32_t t = x0 * a + x1 * b + c;
x0 = x1;
x1 = t;
return x0 >> 2;
}
Here uint32_t is an unsigned 32-bit integer type. Overflows are handled by taking the value modulo 23^2.
Same in Java (note that, although int is signed in Java, overflow is well-defined modulo 23^2 as well):
int next() {
int t = x0 * a + x1 * b + c;
x0 = x1;
x1 = t;
return x0 >>> 2;
}
Initially, all elements of the array contain value 2^31 - 1. For each query, two numbers i and x are generated
with two subsequent calls to next(), that is, with a call “i = next()” followed by “x = next()”. This
stands for the query “a[i % n] = x”.
Suppose the global minimum after i-th query is si. Then you have to find the value
sigma{si * 10099^i mod 2^32}(1 <= i <= q)
Note, that the only purpose of the above generator is to provide you some approximation of the random
generator, you are not expected to find and exploit any its properties. The parameters of the generator
are also chosen to make generated values indeed pseudo-random to the best of our knowledge and belief.
Input
The first and only line of input contains space-separated integers n, q, x0, x1, a, b, c (1 <= n <= 10^7,1 <= q <= 5*10^7, 0 <= x0; x1; c < 2^31, 2 < a; b < 2^31, a and b are odd). Here n is the size of the array, q is
the number of queries, and other values are the parameters of the generator.
Output
Print the single integer: the value of sigma{si * 10099^i mod 2^32}(1 <= i <= q)Examples
standard input standard output
5 5 1 3 5 7 9 2071650652-----------------------------------------------------------------------------------------------
10000 10000 8800 5553535 314159275
271828181 987654321 2620556972
Note
In the first sample, the queries are:
1. a[0] = 8
2. a[2] = 516
3. a[0] = 30276
4. a[4] = 1773386
5. a[3] = 103872918
Page
Source
XVII Open Cup named after E.V. PankratievGrand Prix of Moscow Workshops, Sunday, April 23, 2017
My Solution
题意:都是使用unsigned int 32,q个修改,每次修改一个值,并求出一个当前总区间最小值si,求 sigma{si * 10099^i mod 2^32}(1 <= i <= q),然后每次的修改操作,i和xval[i % n] = x,的i和x都是用给出的随机函数求出。
手写小根堆、卡时间+卡内存、或者随机化
线段树显然很可能超时,所以想用优先队列来做,数组初始值为2^31-1,且生成的x必定小于这个值,所以可以用优先队列来记录这些值,每个元素维护<x, i> 表示当前把val[i]改成了x,然后丢入到优先队列,每次去优先队列顶端,如果d[temp.second] != temp.first 则表示这个值已经不存在于现在的数组中故pop掉。
然后 MLE 12,超内存了,所以手写了一个维护二元组的小根堆,然后过了。
所以时间复杂度 O(q*logq) 而且常数很小,线段树会被卡常数,不优越的优先队列做法也会被卡常数。
空间复杂度 O(n + q) 大概 38+190 MB
好多人用随机化O(n)来做的,毕竟这题确实和随机化有关。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
typedef pair<uint32_t, int> ui;
const int MAXN = 1e7 + 8;
uint32_t x0, x1, c, a, b, val[MAXN], t;
inline uint32_t next(){
t = x0 * a + x1 * b + c;
x0 = x1;
x1 = t;
return x0 >> 2;
}
ui heap[5*MAXN];
int sz = 0;
inline void up(int i){
ui x = heap[i];
for(int j = i / 2; j >= 1; j /= 2) {
if(heap[j].first > x.first){
heap[i] = heap[j];
i = j;
} else {
break;
}
}
heap[i] = x;
}
inline void down(int i){
ui x = heap[i];
for(int j = i * 2; j <= sz; j *= 2){
j += j < sz && heap[j].first > heap[j+1].first;
if(heap[j].first < x.first){
heap[i] = heap[j];
i = j;
} else {
break;
}
}
heap[i] = x;
}
inline void push(const ui &v){
heap[++sz] = v;
up(sz);
}
inline void pop(){
swap(heap[1], heap[sz]);
sz--;
down(1);
}
inline ui top(){
return heap[1];
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n, q;
cin >> n >> q >> x0 >> x1 >> a >> b >> c;
uint32_t s = 1;
int i, j;
uint32_t x, sum=0;
ui temp;
memset(val, 0, sizeof val);
for(j = 0; j < q; j++){
i = next() % n;
x = next();
push(make_pair(x, i));
val[i] = x;
//cout<<x<<endl;
s *= 10099;
temp = top();
while(val[temp.second] != temp.first) pop(), temp = top();
sum += s*temp.first;
}
cout << sum << endl;
return 0;
}
Thank you!
------from ProLights