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('\n');
    } 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 \rightarrow B$,游戏结束当且仅当所有入度为 $0$ 的点都被选

可以筛出所有入度为 $0$ 的点,假设有 $k$ 个,总点数是 $n$,然后安排一下这些点的访问顺序,则答案就是 $\sum\limits_{i=k}^n k \times i \times A_{i-1}^{m-1} \times (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

 

posted @ 2019-04-09 20:12  探险家Mr.H  阅读(287)  评论(0编辑  收藏  举报