[Codeforces 897E. Willem, Chtholly and Seniorious]概率随机+set

[Codeforces 897E. Willem, Chtholly and Seniorious]概率随机+set

分类:math probability random

1. 题目链接

[Codeforces 897E. Willem, Chtholly and Seniorious]

2. 题意描述

有一个序列 a[] ,长度为 n 。然后是m次操作。
操作1:将 al,al+1,,ar 的数,全部加上 x ;
操作2:将al,al+1,,ar的数,全部置位 x ;
操作3:求al,al+1,,ar的数中的第 x 小的数;
操作4:求(ri=laxi)%y;
注意:序列 a[] ,以及所有操作(即 op,l,r,x,y )都是等概率的随机生成的。

数据范围:
1n,m105,0seed<109+7,1vmax109

3. 解题思路

上面四种操作,出现的概率都是 14
假如用线段来描述序列 a[] 中值相同的子序列。当 n=105 时,初始的时候,序列 a[] 随机分布,所以线段很很多。但是经过多次操作2之后,会让这个序列极速收敛,最终收敛到小于 50 左右。然而概率论太差,我并不会证明合并到线段数目小于某一个值的次数的数学期望。
但是自己打印了一下,大概 250 次合并就能让线段数目小于200
然后,知道了这种性质之后,就可以用 set 来保存维护线段。剩下的操作就是暴力删除一堆线段,暴力插入一些线段,暴力对线段进行查询。
所以说,学好概率论太重要啦!

4. 实现代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll infl = 0x3f3f3f3f3f3f3f3fLL;
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }

const int MAXN = 100005;

ll n, m, seed, vmax, a[MAXN];

ll rnd() {
    ll ret = seed;
    seed = (seed * 7 + 13) % 1000000007;
    return ret;
}

struct Line {
    pii itv; ll val;
    Line() {}
    Line(pii itv, ll val) : itv(itv), val(val) {}
    bool operator < (const Line& line) const {
        return itv < line.itv;
    }
};

bool cmp_val(const Line& l1, const Line& l2)  {
    return l1.val < l2.val;
}

set<Line> st;
set<Line>::iterator it, it1, it2;
void oper1(int l, int r, ll x) {
    // [it1, it2)
    it1 = st.upper_bound(Line(pii(l, inf), 0ll)); --it1;
    it2 = st.upper_bound(Line(pii(r, inf), 0ll));
    vector<Line> buf;
    for (it = it1; it != it2; ++it) {
        if ((it->itv).first > r) break;
        buf.push_back(*it);
    }
    st.erase(it1, it2);
    if (buf[0].itv.first < l) {
        st.insert(Line(pii(buf[0].itv.first, l - 1), buf[0].val));
        buf[0].itv.first = l;
    }
    int sz = buf.size();
    if (buf[sz - 1].itv.second > r) {
        st.insert(Line(pii(r + 1, buf[sz - 1].itv.second), buf[sz - 1].val));
        buf[sz - 1].itv.second = r;
    }
    for (Line& line : buf) {
        line.val += x;
        st.insert(line);
    }
    // for(int i = l; i <= r; ++i) a[i] += x;
}

void oper2(int l, int r, ll x) {
    // [it1, it2)
    it1 = st.upper_bound(Line(pii(l, inf), 0ll)); --it1;
    it2 = st.upper_bound(Line(pii(r, inf), 0ll));
    vector<Line> buf;
    for (it = it1; it != it2; ++it) {
        if ((it->itv).first > r) break;
        buf.push_back(*it);
    }
    st.erase(it1, it2);
    if (buf[0].itv.first < l && buf[0].val != x) {
        st.insert(Line(pii(buf[0].itv.first, l - 1), buf[0].val));
        buf[0].itv.first = l;
    }
    int sz = buf.size();
    if (buf[sz - 1].itv.second > r && buf[sz - 1].val != x) {
        st.insert(Line(pii(r + 1, buf[sz - 1].itv.second), buf[sz - 1].val));
        buf[sz - 1].itv.second = r;
    }
    st.insert(Line(pii(buf[0].itv.first, buf[sz - 1].itv.second), x));
    // for(int i = l; i <= r; ++i) a[i] = x;
}

ll oper3(int l, int r, ll x) {
    // [it1, it2)
    it1 = st.upper_bound(Line(pii(l, inf), 0ll)); --it1;
    it2 = st.upper_bound(Line(pii(r, inf), 0ll));
    vector<Line> buf;
    for (it = it1; it != it2; ++it) {
        if ((it->itv).first > r) break;
        buf.push_back(*it);
    }
    if (buf[0].itv.first < l) {
        buf[0].itv.first = l;
    }
    int sz = buf.size();
    if (buf[sz - 1].itv.second > r) {
        buf[sz - 1].itv.second = r;
    }
    sort(buf.begin(), buf.end(), cmp_val);
    ll w = 0;
    for (Line& line : buf) {
        w += (line.itv.second - line.itv.first + 1);
        if (w >= x) return line.val;
    }
    return -1;
}

ll qpow(ll a, ll b, ll mod) {
    ll ret = 1;
    a = a % mod;    // notice here!!!
    while (b > 0) {
        if (b & 1) ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}

ll oper4(int l, int r, ll x, ll y) {
    // [it1, it2)
    it1 = st.upper_bound(Line(pii(l, inf), 0ll)); --it1;
    it2 = st.upper_bound(Line(pii(r, inf), 0ll));
    vector<Line> buf;
    for (it = it1; it != it2; ++it) {
        if ((it->itv).first > r) break;
        buf.push_back(*it);
    }
    if (buf[0].itv.first < l) {
        buf[0].itv.first = l;
    }
    int sz = buf.size();
    if (buf[sz - 1].itv.second > r) {
        buf[sz - 1].itv.second = r;
    }

    ll ret = 0;
    for (Line& line : buf) {
        int w = (line.itv.second - line.itv.first + 1);
        ret += (ll)w * qpow(line.val, x, y) % y;
        ret %= y;
    }
    return ret;
}

int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w+", stdout);
#endif // ___LOCAL_WONZY___
    cin >> n >> m >> seed >> vmax;
    for (int i = 1; i <= n; ++i) a[i] = (rnd() % vmax) + 1;
    st.clear();
    for (int i = 1; i <= n; ++i) {
        int j = i;
        while (j + 1 <= n && a[i] == a[j + 1]) ++j;
        st.insert(Line(pii(i, j), a[i]));
        i = j;
    }

    int op, l, r; ll x, y;
    int cnt = 0;
    for (int i = 1; i <= m; ++i) {
        op = rnd() % 4 + 1;
        l = rnd() % n + 1;
        r = rnd() % n + 1;
        if (l > r) swap(l, r);
        if (op == 3) x = (rnd() % (r - l + 1)) + 1;
        else x = (rnd() % vmax) + 1;
        if (op == 4) y = (rnd() % vmax) + 1;

        // debug(op, l, r, x, y);

        if (op == 1) oper1(l, r, x);
        else if (op == 2) oper2(l, r, x);
        else if (op == 3) {
            ll ret = oper3(l, r, x);
            cout << ret << endl;
        } else {
            ll ret = oper4(l, r, x, y);
            cout << ret << endl;
        }
    }
#ifdef ___LOCAL_WONZY___
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值