• NOI 模拟赛


    三道大原题,我就直接写了

    T1 scoi2016 背单词

    建一个 Trie 树,递推出每个点子树里单词节点的数量,把单词节点拿出来建个树形结构,所有单词节点向他上面最近的单词节点连边,每次贪心往比较小的那边走就可以了

    不建树是错的,因为会把不同的单词节点算成一个

    例如:

    比如左边四个单词节点就被算到了一起,应该先从左边一个一个走,镘走了右边(#上香

    #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;
    }
    const int maxn = 1000010;
    int n;
    char str[maxn];
    int danger[maxn], id[maxn], tr[maxn][26], dfn, size[maxn];
    vector<int> sons[maxn];
    void Insert(char *str) {
        int len = strlen(str), now = 0;
        for(int i=len-1;~i;i--) {
            int pp = str[i] - 'a';
            if(!tr[now][pp]) tr[now][pp] = ++dfn;
            now = tr[now][pp];
        }
        danger[now] = 1;
    }
    int cmp(int x, int y) {return size[x] < size[y];}
    int pnt = 1;
    void dfs(int x, int cur) {
        if(danger[x]) sons[cur].push_back(++pnt), size[cur = pnt] = 1;
        rep(i, 0, 25) if(tr[x][i]) dfs(tr[x][i], cur);
    }
    void makesize(int x) {
        for(int i=0;i<(int)sons[x].size();i++) {
            makesize(sons[x][i]);
            size[x] += size[sons[x][i]];
        }
    }
    int ind[maxn], pre, _tim;
    LL ans;
    void solve(int x, int wfa) {
        _tim++; ans += _tim - wfa; wfa = _tim;
        sort(sons[x].begin(), sons[x].end(), cmp);
        for(int i=0;i<(int)sons[x].size();i++) solve(sons[x][i], wfa);
    }
    int main() {
        //freopen("words.in","r",stdin);
        //freopen("words.out","w",stdout);
        n = read();
        rep(i, 1, n) {
            scanf("%s", str);
            Insert(str);
        } dfs(0, 1); makesize(1);
        //return 0;
        solve(1, 1);
        cout << ans << endl;
    }
    View Code

    T2 sdoi2017 树点染色

    LCT + 线段树套路题,30 分钟码完

    #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;
    }
    const int maxn = 300010;
    int n, q;
    int first[maxn], to[maxn << 1], nx[maxn << 1], cnt;
    inline void add(int u, int v) {
        to[++cnt] = v;
        nx[cnt] = first[u];
        first[u] = cnt;
    } 
    inline void ins(int u, int v) {add(u, v); add(v, u);}
    int anc[maxn], size[maxn], bl[maxn], pos[maxn], _tim, dep[maxn];
    inline void dfs(int x) {
        size[x] = 1;
        for(int i=first[x];i;i=nx[i]) {
            if(to[i] == anc[x]) continue;
            anc[to[i]] = x; dep[to[i]] = dep[x] + 1;
            dfs(to[i]); size[x] += size[to[i]];
        }
    }
    inline void dfs2(int x, int col) {
        bl[x] = col; int k = 0; pos[x] = ++_tim;
        for(int i=first[x];i;i=nx[i]) 
            if(to[i] != anc[x] && size[to[i]] > size[k]) k = to[i];
        if(!k) return;
        dfs2(k, col);
        for(int i=first[x];i;i=nx[i]) 
            if(to[i] != anc[x] && to[i] != k) dfs2(to[i], to[i]);
    }
    int seg[maxn << 2], tag[maxn << 2], mxseg[maxn << 2];
    inline void pushdown_seg(int x, int l, int r) {
        if(tag[x]) {
            int mid = (l + r) >> 1;
            tag[x << 1] += tag[x]; tag[x << 1| 1] += tag[x];
            mxseg[x << 1] += tag[x]; mxseg[x << 1| 1] += tag[x];
            tag[x] = 0;
        }
    }
    inline void update(int x, int l, int r, int L, int R, int v) {
        if(L <= l && r <= R) {
            tag[x] += v;
            mxseg[x] += v;
            return;
        }
        pushdown_seg(x, l, r);
        int mid = (l + r) >> 1;
        if(L <= mid) update(x << 1, l, mid, L, R, v);
        if(R > mid) update(x << 1 | 1, mid + 1, r, L, R, v);
        mxseg[x] = max(mxseg[x << 1], mxseg[x << 1 | 1]);
    }
    inline int querymx(int x, int l, int r, int L, int R) {
        if(L <= l && r <= R) {
            return mxseg[x];
        }
        pushdown_seg(x, l, r);
        int mid = (l + r) >> 1, ans = 0;
        if(L <= mid) ans = max(ans, querymx(x << 1, l, mid, L, R));
        if(R > mid) ans = max(ans, querymx(x << 1 | 1, mid + 1, r, L, R));
        return ans;
    }
    inline void Mod(int x, int opt) {
        update(1, 1, n, pos[x], pos[x] + size[x] - 1, opt);
    }
    inline int lca(int x, int y) {
        while(bl[x] != bl[y]) {
            if(dep[bl[x]] < dep[bl[y]]) swap(x, y);
            x = anc[bl[x]];
        }
        return dep[x] < dep[y] ? x : y;
    }
    inline int qn(int x) {
        return querymx(1, 1, n, pos[x], pos[x] + size[x] - 1);
    }
    #define ls (ch[x][0])
    #define rs (ch[x][1])
    int ch[maxn][2], fa[maxn], st[maxn], top, tg[maxn];
    inline int isroot(int x) {return (ch[fa[x]][0] != x) && (ch[fa[x]][1] != x);}
    inline void pushup(int x) {
        tg[x] = x;
        if(tg[ls]) tg[x] = tg[ls];
    }
    inline void rotate(int x) {
        int y = fa[x], z = fa[y];
        int l = (ch[y][1] == x), r = l ^ 1;
        if(!isroot(y))ch[z][ch[z][1] == y] = x;
        fa[x] = z; fa[y] = x; fa[ch[x][r]] = y;
        ch[y][l] = ch[x][r]; ch[x][r] = y;
        pushup(y); pushup(x);
    }
    inline void splay(int x) {
        while(!isroot(x)) {
            int y = fa[x], z = fa[y];
            if(!isroot(y)) {
                if(ch[z][0] == y ^ ch[y][0] == x) rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
    }
    inline void access(int x) {
        for(int y=0;x;y=x,x=fa[x]) {
            splay(x); int tmp;
            if(rs) {tmp = tg[rs];Mod(tmp, 1);}
            if(y) {tmp = tg[y];Mod(tmp, -1);}
            rs = y; pushup(rs);
        }
    }
    int main() {
        //freopen("tree.in","r",stdin);
        //freopen("tree.out","w",stdout);
        dep[1] = 1;
        n = read(), q = read();
        for(int i=2;i<=n;i++) {
            int u = read(), v = read();
            ins(u, v);
        } dfs(1); dfs2(1, 1);
        rep(i, 1, n) {
            fa[i] = anc[i]; tg[i] = i;
            update(1, 1, n, pos[i], pos[i], dep[i]);
        }
        while(q--) {
            int opt = read();
            if(opt == 1) {
                int x = read();
                access(x);
            }
            if(opt == 2) {
                int x = read(), y = read();
                int hx = lca(x, y);
                int t1 = querymx(1, 1, n, pos[x], pos[x]), t2 = querymx(1, 1, n, pos[y], pos[y]);
                int t3 = querymx(1, 1, n, pos[hx], pos[hx]);
                printf("%d
    ", t1 + t2 - (t3 << 1) + 1);
            }
            if(opt == 3) {
                int x = read();
                printf("%d
    ", qn(x));
            }
        }
    }
    View Code

    T3 hnoi2017 抛硬币

    考场上只写了 30 ,还是太菜了 qnq

    #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;
    }
    const int maxn = 100010;
    LL a, b;
    int mod;
    int ksm(int x, int t) {
        int res = 1;
        while(t) {
            if(t & 1) res = 1LL * res * x % mod;
            x = 1LL * x * x % mod;
            t = t >> 1;
        } return res;
    }
    namespace solve1 {
        int cc[50][50];
        void solve() {
            cc[0][0] = 1;
            rep(i, 1, 30) cc[i][0] = 1;
            rep(i, 1, 30) rep(j, 1, 30) cc[i][j] = (cc[i - 1][j] + cc[i - 1][j - 1]) % mod;
            int maxstate = (1 << a);
            int ans = 0;
            for(int S=1;S<maxstate;S++) {
                int nS = (LL)__builtin_popcount(S) - 1;
                dwn(i, nS, 0) (ans += cc[b][i]) %= mod;
            }
            if(mod == 10) printf("%01d", ans);
            if(mod == 100) printf("%02d", ans);
            if(mod == 1000) printf("%03d", ans);
            if(mod == 10000) printf("%04d", ans);
            if(mod == 100000) printf("%05d", ans);
            if(mod == 1000000) printf("%06d", ans);
            if(mod == 10000000) printf("%07d", ans);
            if(mod == 100000000) printf("%08d", ans);
            if(mod == 1000000000) printf("%09d", ans);
            cout << endl;
        }
    }
    
    namespace solve2 {
        int cc[500][500];
        void solve() {
            cc[0][0] = 1;
            rep(i, 1, 130) cc[i][0] = 1;
            rep(i, 1, 130) rep(j, 1, 130) cc[i][j] = (cc[i - 1][j] + cc[i - 1][j - 1]) % mod;
            int ans = 0;
            rep(i, 1, a) {
                int res = 0;
                rep(j, 0, i-1) (res += cc[b][j]) %= mod;
                (ans += (1LL * cc[a][i] * res) % mod) %= mod;
            }
            if(mod == 10) printf("%01d", ans);
            if(mod == 100) printf("%02d", ans);
            if(mod == 1000) printf("%03d", ans);
            if(mod == 10000) printf("%04d", ans);
            if(mod == 100000) printf("%05d", ans);
            if(mod == 1000000) printf("%06d", ans);
            if(mod == 10000000) printf("%07d", ans);
            if(mod == 100000000) printf("%08d", ans);
            if(mod == 1000000000) printf("%09d", ans);
            cout << endl;
        }
    }
    
    int main() {
        while(scanf("%lld%lld%d", &a, &b, &mod) == 3 ) {
            mod = pow(10, mod);
            if(a <= 100 && b <= 100) solve2::solve();
            else puts("QAQ");
        }
    }
    30pts

    30pts就是:

    $sumlimits_{i=0}^a sumlimits_{j=0}^{b} [i > j] imes C_a^i imes C_b^j$

    也就是 $sumlimits_{i=0}^a sumlimits_{j=0}^{a-i} C_a^{i+j} imes C_b^{i-j}$

    然后根据范德蒙德卷积(链接里的第一个)得到原式就是:$sumlimits_{i=b+1}^{b+a} C_{a+b}^i$

    然后就是组合数取模方面的东西了

    先把式子拆成两部分,记 $c = lceil frac{a+b}{2} ceil$,则原式 = $sumlimits_{i=c}^{a+b} C_{a+b}^i + sumlimits_{i=b+1}^{c} C_{a+b}^i$

    后一项可以暴力,前一项当 $a+b$ 是奇数的时候是杨辉三角的一行和,也就是 $2^{a+b-1}$,当 $a+b$ 是偶数的时候,是 $2^{a+b-1} - frac{1}{2} imes C_{a+b}^{frac{a+b}{2}}$

    然后需要扩展 lucas 求组合数,然而不会

    。。

    补档:扩展 lucas

    要求 $C_n^m space mod space p$,$p$ 不一定是质数

    我们可以唯一分解然后用 excrt 合并一下,现在问题就是求 $C_n^m space mod space p^k$,$p$ 是质数

    根据组合数的定义式,我们只要快速求出模意义下的阶乘就可以了

    举个简单的例子:

    $22! space mod space 3^2$

    发现 $22! = (3^7) imes (1 imes 2 imes 3 imes ... imes 7) imes (1 imes 2 imes 4 imes 5 imes 7 imes 8 imes 10 imes 11 imes 13 imes 14 imes 16 imes 17 imes 19 imes 22)$

    第一个括号是 $p^{lfloor frac{n}{p} floor}$,第二个括号是 $(lfloor frac{n}{p} floor) !$ ,递归解决,第三个括号在模意义下存在一个循环,循环了 $lfloor frac{n}{p^k} floor$ 次,每次是 $prodlimits_{i=1}^{p^k} i imes [gcd(i,p)==1]$ ,可以先算这一个循环,然后算它的 $lfloor frac{n}{p^k} floor$ 次幂,最后还剩了 $n space mod space p^k$ 项,注意到每一项有贡献当且仅当它与 $p$ 互质,暴力算即可

    算组合数的时候,可以把所有 $p$ 提到分数外面,这样就有逆元了,也就是你要算 $frac{frac{n!}{p^{p_1}}}{frac{m!}{p^{p_2}} imes frac{(n-m)!}{p^{p_3}}} imes p^{p_1-p_2-p_3}$

    $p_1,p_2,p_3$ 可以递推算一下

    然后在算阶乘的时候其实并不用算第一部分,因为不算第一部分算出来的是 $frac{n!}{p^{p_1}}$,就不用除了

    复杂度大概是 $O(plogp)$

    #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;
        for (ch = getchar(); !isdigit(ch); ch = getchar())
            if (ch == '-')
                f = -f;
        for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    const int mod = 1e9, maxn = 2e6 + 10;
    LL a, b;
    int pp, k2, k5, fac2[maxn], fac5[maxn];
    inline int ksm(int x, LL t, int md) {
        int res = 1;
        while (t) {
            if (t & 1)
                res = 1LL * res * x % md;
            x = 1LL * x * x % md;
            t = t >> 1;
        }
        return res;
    }
    inline void exgcd(LL a, LL b, LL &x, LL &y) {
            if(!b) {
                    x = 1, y = 0;
                    return;
            }
            exgcd(b, a%b, y, x);
            y -= a / b * x;
    }
    LL x, y;
    inline LL inv(LL a, LL md) {
            x = 0, y = 0;
            exgcd(a, md, x, y);
            return (x + md) % md;
    }
    void print(int ans) {
        // cout << pp << " " << ans << endl;
        int md = pow(10, pp);
        ans %= md;
        if (pp == 1)
            printf("%01d", ans);
        if (pp == 2)
            printf("%02d", ans);
        if (pp == 3)
            printf("%03d", ans);
        if (pp == 4)
            printf("%04d", ans);
        if (pp == 5)
            printf("%05d", ans);
        if (pp == 6)
            printf("%06d", ans);
        if (pp == 7)
            printf("%07d", ans);
        if (pp == 8)
            printf("%08d", ans);
        if (pp == 9)
            printf("%09d", ans);
        cout << endl;
    }
    LL fc1(LL n, int type) {
        LL ans = 0, p = type ? 2 : 5;
        for (LL i = n; i; i /= p) ans += i / p;
        return ans;
    }
    LL fc2(LL n, int type) {
            if(!n) return 1;
            int md = type ? k2 : k5;
            int s = type ? fac2[md] : fac5[md];
            s = ksm(s, n / md, md);
            s = 1LL * s * (type ? fac2[n % md] : fac5[n % md]) % md;
            return s * fc2(n / (type ? 2 : 5), type) % md;
    }
    int aa, bb;
    LL tms, cur, ret;
    int C(LL n, LL m, int type, int div) {
        int md = type ? k2 : k5;
        if (n < m)
            return 0;
        tms = fc1(n, type) - fc1(m, type) - fc1(n - m, type);
        if (div && type) tms--;
        cur = ksm((type ? 2 : 5), tms, md);
        if(div && !type)cur = cur * inv(2, md);
        if (tms >= 9) return 0;
        ret = fc2(n, type) * inv(fc2(m, type), md) % md * inv(fc2(n - m, type), md) % md * cur % md;
        return ret;
    }
    int getC(LL n, LL m, int div) {
        int ans = 0;
        aa = C(n, m, 1, div), bb = C(n, m, 0, div);
        aa = aa * (mod/k2) %mod * inv(mod/k2, k2) %mod;
        ans = (ans + aa) %mod;
        
        bb = bb * (mod/k5) %mod * inv(mod/k5, k5) %mod;
        ans = (ans + bb) %mod;
        return ans;
    }
    int main() {
        k2 = ksm(2, 9, 1e9);
        k5 = ksm(5, 9, 1e9);
        fac2[0] = fac5[0] = 1;
        rep(i, 1, k2) if (i % 2) fac2[i] = 1LL * fac2[i - 1] * i % k2;
        else fac2[i] = fac2[i - 1];
        rep(i, 1, k5) if (i % 5) fac5[i] = 1LL * fac5[i - 1] * i % k5;
        else fac5[i] = fac5[i - 1];
        while (scanf("%lld%lld%d", &a, &b, &pp) == 3) {
            int ans = ksm(2, a + b - 1, 1e9);
            for (LL i = b + 1; i <= (a + b) / 2; i++) (ans += getC(a + b, i, 0)) %= mod;
            if (!((a + b) & 1))
                (ans += (mod - getC(a + b, ((a + b) >> 1), 1))) %= mod;
            print(ans);
        }
    }
    100pts
    #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;
        for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
        for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
        return x * f;
    }
    LL n, m, p;
    inline LL ksm(LL x, LL t, LL mod) {
        LL res = 1;
        while(t) {
            if(t & 1) (res *= x) %= mod;
            (x *= x) %= mod;
            t = t >> 1;
        } return res;
    }
    inline void exgcd(LL a, LL b, LL &x, LL &y) {
        if(!b) {
            x = 1, y = 0;
            return;
        }
        exgcd(b, a%b, y, x);
        y -= (a / b) * x;
    }
    inline LL inv(LL a, LL mod) {
        LL x, y;
        exgcd(a, mod, x, y);
        return (x + mod) % mod;
    }
    #define mp make_pair
    pair<LL, LL> a, b;
    inline LL fc1(LL n, LL p) {
        int ans = 0;
        for(LL i = n; i; i /= p) ans += (i / p);
        return ans;
    }
    inline LL fc2(LL n, LL p, LL pr) {
        if(!n) return 1;
        LL s = 1;
        rep(i, 1, pr) if(i % p) s = 1LL * s * i % pr;
        s = ksm(s, n / pr, pr);
        rep(i, 1, n % pr) if(i % p) s = 1LL * s * i % pr;
        return s * fc2(n / p, p, pr) % pr;
    }
    inline LL C(LL n, LL m, LL p, LL tms) {
        LL pr = pow(p, tms), px = fc1(n, p) - fc1(m, p) - fc1(n - m, p);
        if(px >= tms) return 0;
        LL res = fc2(n, p, pr) * inv(fc2(m, p, pr), pr) % pr * inv(fc2(n - m, p, pr), pr) % pr;
        return ksm(p, px, pr) * res % pr;
    }
    pair<LL, LL> merge(pair<LL, LL> a, pair<LL, LL> b) {
        LL t = __gcd(a.second, b.second);
        LL gm = b.second / t, M = gm * a.second;
        pair<LL, LL> c;
        c.first = ((LL) inv(a.second / t, gm) * ((b.first - a.first) / t) % gm * a.second + a.first) % M;
        c.second = M; if(c.first < 0) c.first += M;
        return c;
    }
    int main() {
        cin >> n >> m >> p;
        a = mp(0, 1);
        for(LL i=2;i<=p;i++) if(p % i == 0) {
            LL tms = 0, cur = 1;
            while(p % i == 0) tms++, cur *= i, p /= i;
            b = mp(C(n, m, i, tms), cur);
            a = merge(a, b);
        }
        cout << a.first << endl;
    }
    组合数取模

    代码暂时没拿到,先咕,明天补

    我卢本伟没有咕咕

  • 相关阅读:
    Openrasp源码分析
    feifeicms后台任意文件读取
    python之迭代器和生成器
    java之导入excel
    jquery单击事件的写法
    java之高效操作文件
    多条件搜索优化sql
    java之代码复用
    java之接口文档规范
    eclipse之常用快捷键
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10526964.html
Copyright © 2020-2023  润新知