XVII Open Cup named after E.V. Pankratiev Problem I. Rage Minimum Query 手写小根堆、卡时间+卡内存、或者随机化

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. Pankratiev
Grand 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和x

val[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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值