zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    人生转折点:弃文从理
    人生第一站:大三暑假实习僧
    监听器启动顺序和java常见注解
    java常识和好玩的注释
    182. Duplicate Emails (Easy)
    181. Employees Earning More Than Their Managers (Easy)
    180. Consecutive Numbers (Medium)
    178. Rank Scores (Medium)
    177. Nth Highest Salary (Medium)
    176. Second Highest Salary(Easy)
  • 原文地址:https://www.cnblogs.com/v-vip/p/9614289.html
Copyright © 2011-2022 走看看