zoukankan      html  css  js  c++  java
  • NOI 模拟赛

    管老师的题!

    T1

    给一个序列,多次询问一个区间去重排序后满足每一项是前一项 +1 ,长度为 1,2,...10 的极长子区间个数

    $n leq 10^6$

    sol:

    正解不懂,考场上莫队打挂,考后发现莫队就过了...

    每个数插进去之后在他值域的前面 $10$ 个后面 $10$ 个找一下即可

    #pragma GCC optimize("Ofast,no-stack-protector")
    #pragma GCC optimize("O3")
    #pragma GCC target("avx")
    #include <bits/stdc++.h>
    #define LL long long
    #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
    using namespace std;
    namespace IO{
        const int BS=(1<<23)+5; int Top=0;
        char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1;
        char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;}
        void flush(){fwrite(OT,1,OS-OT,stdout);}
        void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;}
        void write(int x){
            if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-');
            while(x) SS[++Top]=x%10,x/=10;
            while(Top) Putchar(SS[Top]+'0'),--Top;
        }
        int read(){
            int nm=0,fh=1; char cw=Getchar();
            for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
            for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
            return nm*fh;
        }
    } using namespace IO;
    const int maxn = 2e6 + 10;
    int n, q, mx, a[maxn], bl[maxn], cnt[maxn], ans[13], fans[maxn][13];
    struct Ques { int l, r, id; } qs[maxn];
    inline void inc(int x) {
        cnt[x]++;
        if(cnt[x] > 1) return;
        int pnt = 0, lpos = x, rpos = x;
        rep(i, x + 1, min(mx, x + 11)) {
            if(!cnt[i]) break;
            pnt++; rpos = i;
        }
        ans[pnt]--;
        pnt = 0;
        dwn(i, x - 1, max(1, x - 11)) {
            if(!cnt[i]) break;
            pnt++; lpos = i;
        }
        ans[pnt]--;
        if(rpos - lpos + 1 <= 10) ans[rpos - lpos + 1]++;
    }
    inline void dec(int x) {
        cnt[x]--;
        if(cnt[x] > 0) return;
        int pnt = 0;
        int lpos = x, rpos = x;
        dwn(i, x - 1, max(1, x - 11)) {
            if(!cnt[i]) break;
            pnt++;
            lpos = i;
        } ans[pnt]++;
        pnt = 0;
        rep(i, x + 1, min(mx, x + 11)) {
            if(!cnt[i]) break;
            pnt++;
            rpos = i;
        } ans[pnt]++;
        if(rpos - lpos + 1 <= 10) ans[rpos - lpos + 1]--;
    }
    int main() {
        //freopen("t1.in","r",stdin);
        //freopen("t1.owt","w",stdout);
        n = read(), q = read(); int SZ = sqrt(n);
        rep(i, 1, n) mx = max(mx, (a[i] = read())), bl[i] = (i - 1) / SZ + 1;
        rep(i, 1, q) qs[i].l = read(), qs[i].r = read(), qs[i].id = i;
        sort(qs + 1, qs + q + 1, [](const Ques &a, const Ques &b) 
        {
            return (bl[a.l] == bl[b.l]) ? ((bl[a.l] & 1) ? (a.r < b.r) : (a.r > b.r)) : a.l < b.l;
        });
        int l = qs[1].l, r = qs[1].l - 1;
        rep(i, 1, q) {
            while(l > qs[i].l) l--, inc(a[l]);
            while(r < qs[i].r) r++, inc(a[r]);
            while(l < qs[i].l) dec(a[l]), l++;
            while(r > qs[i].r) dec(a[r]), r--;
            memcpy(fans[qs[i].id], ans, sizeof(ans));
        }
        rep(i, 1, q) {
            rep(j, 1, 10) Putchar('0' + fans[i][j] % 10);
            Putchar('
    ');
        } flush();
    }
    /*
    10 5
    1 1 3 3 5 5 7 7 9 15
    1 10
    2 4
    3 5
    5 5
    10 10
    5000000000
    2000000000
    2000000000
    1000000000
    1000000000
    */
    View Code

    T2

    给一个数 $n$,$n$ 以内随机一个数 $x$,然后给定一个概率 $p$,有 $p$ 的概率选一个 $1 sim n-1$ 以内与 $x$ 异或值最大的数与 $x$ 异或,$1-p$ 的概率选一个 $1 sim n-1$ 的随机数与 $x$ 异或,求异或值的期望

    $n leq 10^{18}$

    sol:

    发现两部分可以分开统计,都随机那个按位搞一下就行了,最大的那个可以考虑 $n-1$ 这个数每一位的贡献

    显然,如果 $n-1$ 某一位是 $1$,则比这一位小的都可以是 $1$,如果是 $0$ 就扔下去继续算就可以了,可以逐位统计这一位有多少个 $1$ 来算贡献

    #include <bits/stdc++.h>
    #define LL long long
    #define DB long double
    #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f;
        for(; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    LL n; double p; DB ans; int dig[70], top;
    int main() {
        cin >> n >> p; LL cur = n - 1;
        while(cur) { dig[++top] = cur % 2; cur = cur >> 1; }
        dwn(i, top, 1) {
            LL f = cur;
            if(dig[i]) { f += (((n - 1) & ((1LL << (i - 1))) - 1) + 1), cur += (1LL << (i - 2)); }
            ans += 1.0 * f * (n - f) * 2 * (1LL << (i - 1));
        } ans = 1.0 * ans / n; ans = 1.0 * ans / n;
        DB re = 1.0 * n * ((1LL << (top)) - 1);
        cur = (1LL << (top));
        dwn(i, top, 1) {
            if(dig[i]) cur >>= 1;
            else re -= 1.0 * (cur >> 1) * (1LL << (i - 1));
        } re = 1.0 * re / n;
        ans = ans * (1 - p) + re * p; double output = ans;
        cout << fixed << showpoint << setprecision(6) << output << endl;
    }
    View Code

    T3

    有 $n$ 个编号为 $[L,R]$ 的人,你每次标记一个人就要标记所有编号为他的倍数的人,有标记的可以再选一遍,但主动选过一遍的就不能再选,如果所有人都被标记,游戏结束,求所有方案的主动选次数和,膜 $10^9+7$

    $L,R leq 10^7$

    sol:

    按整除关系建一张图,如果 $A$ 能整除 $B$ 就连 $A ightarrow B$,游戏结束当且仅当所有入度为 $0$ 的点都被选

    可以筛出所有入度为 $0$ 的点,假设有 $k$ 个,总点数是 $n$,然后安排一下这些点的访问顺序,则答案就是 $sumlimits_{i=k}^n k imes i imes A_{i-1}^{m-1} imes (n-k)!$

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    #define LL long long
    #define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f;
        for(; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    int L, R;
    const int maxn = 1e7 + 10, mod = 1e9 + 7;
    int pri[maxn], tot, chk[maxn];
    int fac[maxn], ifac[maxn];
    inline int ksm(int x, int t, int res = 1) {
        for(; t; x = 1LL * x * x % mod, t = t >> 1)
            if(t & 1) res = 1LL * x * res % mod; return res;
    }
    void sieve() {
        rep(i, L, R) if(!chk[i]) {
            pri[++tot] = i;
            for(register int j = i + i; j <= R; j += i) chk[j] = 1;
        }
    }
    inline int A(int x, int y) {
        if(y > x) return 0;
        return 1LL * fac[x] * ifac[x - y] % mod;
    }
    int main() {
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        L = read(), R = read(); sieve();
        fac[0] = 1, ifac[0] = ifac[1] = 1;
        rep(i, 1, R) fac[i] = 1LL * fac[i - 1] * i % mod;
        rep(i, 2, R) ifac[i] = 1LL * (mod - (mod / i)) * ifac[mod % i] % mod;
        rep(i, 1, R) ifac[i] = 1LL * ifac[i] * ifac[i - 1] % mod; 
        int ans = 0; rep(i, tot, R - L + 1) ans = (ans + 1LL * i * A(i - 1, tot - 1)) % mod;
        cout << 1LL * (1LL * ans * fac[R - L + 1 - tot] % mod) * tot % mod << endl;
    }
    View Code
  • 相关阅读:
    iOS开发之窗口和视图
    GCD
    禁止非法用户登录综合设置
    大数减法(C++实现)
    大数加法(C++实现)
    迷宫问题 (BFS ➕输出路径)
    Pots (BFS ➕ 输出路径)
    Shuffle'm Up (map ➕ BFS)
    Prime Path (BFS)
    速算24点
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10679364.html
Copyright © 2011-2022 走看看