• 18/9/9牛客网提高组Day1


          牛客网提高组Day1

    T1 中位数

      这好像是主席树??听说过,不会啊。。。

      最后只打了个暴力,可能是n2logn?

      只过了前30%  qwq

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int M = 100005;
    int n, len;
    int tmp, ans;
    int a[M];
    struct nond {
        int id, num;
    }e[M];
    
    bool cmp1(nond x, nond y) {
        return x.num < y.num;
    }
    bool cmp2(nond x, nond y) {
        return x.id < y.id;
    }
    
    int main() {
        scanf("%d%d", &n, &len);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &e[i].num);
            e[i].id = i;
        }
        for (int i = 1; i + len - 1 <= n; i++)
            for (int j = i + len - 1; j <= n; j++) {
                sort(e + i, e + j + 1, cmp1);
                if ((j - i + 1) & 1) tmp = e[(j + i) / 2].num;
                else tmp = e[(j + i - 1) / 2].num;
                ans = max(ans, tmp);
                sort(e + i, e + j, cmp2);
            }
        printf("%d
    ", ans);
        return 0;
    }
    考场代码

    正解:

      二分求最终可能的答案x,把>x的数字记为1,<=x的数字记为-1。检验是否存在和>=0的区间。可以维护前缀和的前缀最小值

     复杂度:O(nlogA[i])

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100005;
    int a[maxn], n, L;
    
    bool test(int z) {
        static int b[maxn];
        for(int i = 1; i <= n; i ++)
            if (a[i] >= z) b[i] = 1;
            else b[i] = -1;
        for(int i = 1, mi = (1 << 30); i <= n; i ++) {
            if (i >= L) mi = min(mi, b[i - L]);
            b[i] += b[i - 1];
            if (i >= L && b[i] - mi > 0) return 1;
        }
        return 0;
    }
    
    int main() {
    //    freopen("median.in","r",stdin);
    //    freopen("median.out","w",stdout);
        scanf("%d%d", &n, &L);
        for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
        int l = 0, r = int(1e9), tmp;
        for(int mid; l <= r;) {
            mid = l + r >> 1;
            if (test(mid)) tmp = mid, l = mid + 1;
            else r = mid - 1;
        }
        printf("%d
    ", tmp);
        return 0;
    }
    std

    T2 数数字

      暴力枚举区间[L, R]中的每一个数,用一个check函数判断每个数的每个位上的数的乘积是否在区间[L1, R1]中,记录答案

      本来还想拿L1, R1<=1000的20分来,然后。。。yy了一会,没想出来咋写,so。。只交了40分暴力

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    typedef long long LL;
    LL l, r, l1, r1;
    LL ans;
    
    LL check2(int x) {
        LL res = 1;
        while(x) {
            int tmp = x % 10;
            res *= tmp;
            x /= 10;
        }
        if(res >= l1 && res <= r1) return 1;
        else return 0;
    }
    
    int main() {
        scanf("%lld%lld%lld%lld", &l, &r, &l1, &r1);
        for(int i = l; i <= r; i++)
            if(check2(i)) ans++;
        printf("%lld
    ", ans);
        return 0;
    }
    考场代码

    正解:

      记忆化搜索或数位DP

      这几天刚好在做数位DP的题,然而并不会 qwq

     DP做法:

      由于数位乘积只是由0到9,可以把L1,R1分类讨论,假如区间包含0,则原来的数字分为包含至少一个零,和完全不包含0两类。前一类可以使用简单的数位DP计算。接下来介绍后一类。

      由于只包含1到9,所以只用记录乘积的质因数分解中,出现了多少2,3,5,7。题目中的L1,R1不超过10^18,可以计算出2最多为59个,3最多为37, 5最多为26,7最多为21。设F[i][c_2][c_3][c_5][c_7]表示考虑到第i位,乘积状态为c_2,c_3,c_5,c_7的数位DP情况。接着就是经典数位DP做法。空间可能比较紧,需要用滚动数组。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int co[10][10];
    ll l, r, l1, r1;
    ll pw[10][100];
    
    inline int merge(int i, int cr, int b) {
        return (cr > b ? 2 : (cr == b ? i : 0));
    }
    
    ll calc_no_zero(ll x) {
        if (x <= 0) return 0;
        static ll f[2][3][60][38][27][22];
        memset(f,0,sizeof f);
        int cr = 0;
        f[0][1][0][0][0][0] = 1;
        ll ans = 0, val;
        for(; x; x /= 10, cr ^= 1) {
            int bit = x % 10;
            memset(f[cr ^ 1], 0, sizeof f[cr]);
            for(int i = 0; i < 3; i ++)
                for(int n_2 = 0; n_2 < 60; n_2 ++)
                    for(int n_3 = 0; n_3 < 38; n_3 ++)
                        for(int n_5 = 0; n_5 < 27; n_5 ++)
                            for(int n_7 = 0; n_7 < 22; n_7 ++)
                                if (val = f[cr][i][n_2][n_3][n_5][n_7]) {
                                    ll q1 = r1 / pw[2][n_2] / pw[3][n_3] / pw[5][n_5] / pw[7][n_7];
                                    ll p1 = (l1 - 1) / pw[2][n_2] / pw[3][n_3] / pw[5][n_5] / pw[7][n_7];
                                    if (q1 >= 1 && p1 <= 0) ans += val;
                                    if (q1 <= 0) continue;
                                    for(int p = 1; p < 10; p ++) {
                                        int ni = merge(i, p, bit);
                                        int c_2 = n_2 + co[p][2];
                                        int c_3 = n_3 + co[p][3];
                                        int c_5 = n_5 + co[p][5];
                                        int c_7 = n_7 + co[p][7];
                                        if (c_2 >= 60 || c_3 >= 38 || c_5 >= 27 || c_7 >= 22) continue;
                                        f[cr ^ 1][ni][c_2][c_3][c_5][c_7] += val;
                                    }
                                }
        }
        for(int i = 0; i < 2; i ++)
            for(int n_2 = 0; n_2 < 60; n_2 ++)
                for(int n_3 = 0; n_3 < 38; n_3 ++)
                    for(int n_5 = 0; n_5 < 27; n_5 ++)
                        for(int n_7 = 0; n_7 < 22; n_7 ++)
                            if (val = f[cr][i][n_2][n_3][n_5][n_7]) {
                                ll q1 = r1 / pw[2][n_2] / pw[3][n_3] / pw[5][n_5] / pw[7][n_7];
                                ll p1 = (l1 - 1) / pw[2][n_2] / pw[3][n_3] / pw[5][n_5] / pw[7][n_7];
                                if (q1 >= 1 && p1 <= 0) ans += val;
                            }
        return ans;
    }
    
    ll calc_with_zero(ll x) {
        if (l1) return 0;
        static ll g[2][3][2][2];
        memset(g, 0, sizeof g);
        int cr = 0;
        ll ans = 0;
        g[0][1][0][0] = 1;
        for(; x; x /= 10, cr ^= 1) {
            int bit = x % 10;
            memset(g[cr ^ 1], 0, sizeof g[cr]);
            for(int i = 0; i < 3; i ++)
                for(int j = 0; j < 2; j ++)
                    for(int hd = 0; hd < 2; hd ++)
                        if (g[cr][i][j][hd]) {
                            if (hd && j) ans += g[cr][i][j][hd];
                            for(int p = 0; p < 10; p ++) {
                                int ni = merge(i, p, bit);
                                int nj = (j | (p == 0));
                                int hdt = (p > 0);
                                g[cr ^ 1][ni][nj][hdt] += g[cr][i][j][hd];
                            }
                        }
        }
        return ans + g[cr][0][1][1] + g[cr][1][1][1];
    }
    
    ll calc(long long x) {
        return calc_no_zero(x) + calc_with_zero(x);
    }
    
    int main() {
    //    freopen("count.in","r",stdin);
    //    freopen("count.out","w",stdout);
        for(int i = 1; i < 10; i ++) {
            for(int j = 2; j < 10; j ++)
                for(int k = i; k % j == 0; k /= j)
                    co[i][j] ++;
            pw[i][0] = 1;
            for(int j = 1; j <= 60; j ++)
                pw[i][j] = pw[i][j - 1] * i;
        }
        cin >> l >> r >> l1 >> r1;
        ll ans = 0;
        if (!l) ans += (l1 == 0), ++ l;
        if (l <= r) ans += calc(r) - calc(l - 1);
        cout << ans << endl;
        return 0;
    }
    std

    T3 保护

      表示只能想到最暴力的方法:

       建树后,根据军队保护的范围枚举,为边加边权,然后每个重要人物到根节点的路径也挨个枚举   但是好像写挂了,一分没有 qwq

      想过树剖+线段树的做法:

       树剖,然后线段树维护区间最小值,军队的保护可以做线段树的区间加法

       也不知道对不对的做法,关键是不会啊  弱的一批

      好像还有些用倍增做的童鞋,然而出了奇奇怪怪的错误,导致。。。

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    const int M = 200005;
    int n, m, t, tot;
    int cap[M*2];
    int to[M*2], net[M*2], head[M];
    int deep[M], top[M], size[M], dad[M];
    struct nond {
        int id, sum;
        int v, k;
    } e[M];
    
    void add(int u, int v) {
        to[++tot] = v; net[tot] = head[u]; head[u] = tot;
        to[++tot] = u; net[tot] = head[v]; head[v] = tot;
    }
    
    void dfs(int now) {
        size[now] = 1;
        deep[now] = deep[dad[now]] + 1;
        for (int i = head[now]; i; i = net[i])
            if (to[i] != dad[now]) {
                dad[to[i]] = now;
                dfs(to[i]);
                size[now] += size[to[i]];
            }
    }
    
    void dfsl(int now) {
        int t = 0;
        if (!top[now]) top[now] = now;
        for (int i = head[now]; i; i = net[i])
            if (to[i] != dad[now] && size[t] > size[to[i]])
                t = to[i];
        if (t) {
            top[t] = top[now];
            dfsl(t);
        }
        for (int i = head[now]; i; i = net[i])
            if (to[i] != dad[now] && to[i] != t)
                dfsl(to[i]);
    }
    
    int lca(int x, int y) {
        while (top[x] != top[y]) {
            if (deep[top[x]] < deep[top[y]])
                swap(x, y);
            x = dad[top[x]];
        }
        return deep[x] > deep[y] ? y : x;
    }
    
    void change(int u, int v) {
        for (int i = head[v]; i; i = net[i]) {
            if (to[i] == u) {
                for (int j = head[u]; j; j = net[j])
                    if (to[j] == v) { cap[j]++; break; }
                cap[i]++; return ;
            }
            if (to[i] = dad[v]) {
                cap[i]++;
                for (int j = head[u]; j; j = net[j])
                    if (to[j] == v) cap[j]++;
            } v = dad[v];
        }
    }
    
    void fun(int now) {
        int u = e[now].v, tmp = e[now].k;
        for (int i = head[u]; i; i = net[i]) {
            if (to[i] == 1) if (cap[i] >= tmp) { e[now].sum++; return ; }
            if (to[i] == dad[u])
                if (cap[i] >= tmp) e[now].sum++, u = dad[u];
        }
    }
    
    bool cmp1(nond x, nond y) {
        if (deep[x.v] == deep[y.v]) return x.k > y.k;
        return deep[x.v] > deep[y.v];
    }
    bool cmp2(nond x, nond y) {
        return x.id < y.id;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i < n; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
        }
        dfs(1); dfsl(1);
        for (int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            if (u == v) continue;
            int S = lca(u, v);
    //        printf("%d
    ", S);
            if (S == u) change(S, v);
            else if (S == v) change(S, u);
            else change(S, u), change(S, v);
        }
        scanf("%d", &t);
        for (int i = 1; i <= t; i++) 
            scanf("%d%d", &e[i].v, &e[i].k);
        sort(e + 1, e + t + 1, cmp1);
        for (int i = 1; i <= t; i++)
            if (e[i].v == e[i - 1].v) e[i].sum = e[i - 1].sum;
            else fun(i);
        sort(e + 1, e + t + 1, cmp2);
        for (int i = 1; i <= t; i++)
            printf("%d
    ", e[i].sum);
        return 0;
    }
    考场代码,求路过dalao指正 qwq

    正解:

      启发式合并维护子树的线段树。询问时可以在维护出来的u的那棵线段树上走,相当于找第k小数。复杂度O((n+q)logn)。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200005;
    struct node {
        int l,r,cnt;
    } T[maxn * 100];
    
    vector<int> lk[maxn];
    int fa[maxn][20], dep[maxn], ord[maxn], cnt, n, m, ans[maxn];
    
    void dfs(int now, int pre) {
        dep[now] = dep[pre] + 1;
        fa[now][0] = pre;
        for (int i = 1; (1 << i) <= dep[now]; i++) fa[now][i] = fa[fa[now][i - 1]][i - 1];
        for (int i = 0; i < lk[now].size(); i ++)
            if (lk[now][i] != pre)
                dfs(lk[now][i], now);
    }
    
    void insert(int l, int r, int p, int &jd) {
        if (!jd) jd = ++ cnt;
        T[jd].cnt ++;
        if (l == r) return;
        int mid = l + r >> 1;
        if (p <= mid) insert(l, mid, p, T[jd].l);
        else insert(mid + 1, r, p, T[jd].r);
    }
    
    int merge(int l, int r, int a, int b) {
        if ((!a) || (!b)) return a + b;
        int jd = ++ cnt;
        T[jd].cnt = T[a].cnt + T[b].cnt;
        if (l == r) return jd;
        int mid = l + r >> 1;
        T[jd].l = merge(l, mid, T[a].l, T[b].l);
        T[jd].r = merge(mid + 1, r, T[a].r, T[b].r);
        return jd;
    }
    
    int find_k(int l, int r, int k, int jd) {
        if (T[jd].cnt < k) return (1 << 30);
        if (l == r) return l;
        int mid = l + r >> 1;
        if (T[T[jd].l].cnt >= k) return find_k(l, mid, k, T[jd].l);
        return find_k(mid + 1, r, k - T[T[jd].l].cnt, T[jd].r);
    }
    
    void dfs_w(int now, int pre) {
        for(int i = 0; i < lk[now].size(); i ++)
            if (lk[now][i] != pre) {
                dfs_w(lk[now][i], now);
                ord[now] = merge(1, n, ord[now], ord[lk[now][i]]);
            }
    }
    
    int get_lca(int u, int v) {
        if (dep[u] > dep[v]) swap(u,v);
        for(int i = 18; i + 1; i --)
            if (dep[fa[v][i]] >= dep[u]) v = fa[v][i];
        if (u == v) return u;
        for(int i = 18; i + 1; i --)
            if (fa[v][i] != fa[u][i]) v = fa[v][i], u = fa[u][i];
        return fa[u][0];
    }
    
    int main() {
    //    freopen("guard.in","r",stdin);
    //    freopen("guard.out","w",stdout);
        scanf("%d%d", &n, &m);
        for(int i = 1, u, v; i < n; i ++) {
            scanf("%d%d", &u, &v);
            lk[u].push_back(v), lk[v].push_back(u);
        }
        dfs(1, 0);
        for(int i = 1, u, v; i <= m; i ++) {
            scanf("%d%d", &u, &v);
            int p = get_lca(u, v);
            insert(1, n, dep[p], ord[u]), insert(1, n, dep[p], ord[v]);
        }
        dfs_w(1, 0);
        int q;
        scanf("%d", &q);
        for(int i = 1; i <= q; i ++) {
            int u, k;
            scanf("%d%d", &u, &k);
            printf("%d
    ", max(0, dep[u] - find_k(1, n, k, ord[u])));
        }
        return 0;
    }
    std
  • 相关阅读:
    Linux下PCI设备驱动程序开发 PCI驱动程序实现(三)
    一个动态内存管理模块的实现
    【Linux device driver】设备驱动程序概述(一)
    Linux PCI设备驱动程序开发 PCI 体系结构(一)
    [linux driver]用I/O命令访问PCI总线设备配置空间
    【Linux device driver】网络设备驱动程序(二)
    【Linux device driver】网络设备驱动注意的问题(三)
    C++中的引用、const引用和非const引用
    C++的数组和指针
    “指向const对象的指针” 和 “const指针”
  • 原文地址:https://www.cnblogs.com/v-vip/p/9614289.html
Copyright © 2020-2023  润新知