zoukankan      html  css  js  c++  java
  • 牛客网 nowcoder TG test-172

    # solution-nowcoder-172


    # A-中位数


    • $30\%:nle 200$
      • 直接枚举 $n-len+1$ 个区间,将这段里的数重新排序直接找到中位数
    • $60\%:nle 2000$
      • 用主席树维护,查询区间第 $k$ 小。时间复杂度是 $Theta(n^2log ^2n)$,我只过了 $50$ 分。应该是用平衡树维护,时间复杂度是$Theta(n^2log n)
    • $100\%:nle 10^5$
      • 前缀和 $+$ 前缀最小值 $+$ 二分答案。二分一个 $mid$,判断一下行不行,如何判断?在长度为 $n$ 的序列中,用一个b数组记录一下,$a[i]>mid ightarrow b[i]=1,a[i]<=mid ightarrow b[i]=-1.$ 然后记录b数组的前缀和sum,边记录边维护前缀最小值,如果现在扫到的下标已经可以和前面的构成一个合法的区间了。那么就可以判断如果 $sum[i]-sum_{min}>0$ 证明可以最为中位数,return true。

    # 代码

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while (c <= '9' && c >= '0') {x = x*10 + c-'0'; c = getchar();}
        return x * f;
    }
    const int maxn = 1e5+3;
    int n, m, a[maxn], mx;
    inline bool judge(int x) {
        static int b[maxn];
        for(int i=1; i<=n; i++) {
            if(a[i] < x) b[i] = -1;
            else b[i] = 1;
        }
        int mn = 2147483647;
        for(int i=1; i<=n; i++) {
            if(i >= m) mn = min(mn, b[i-m]);
            b[i] = b[i-1] + b[i];
            if(i >= m && b[i] - mn > 0) return true;
        }
        return false;
    }
    int main() {
        n = read(), m = read();
        for(int i=1; i<=n; i++)
            a[i] = read(), mx = max(mx, a[i]);
        static int l = 0, r = mx, mid, ans;
        while (l <= r) {
            mid = (l + r) >> 1;
            if(judge(mid))
                l = mid+1, ans = mid;
            else r = mid-1;
        }
        printf("%d", ans);
    }

    # B-数数字


    # 解题思路

    数位 $dp$,看上去好像有$10^{18}$ 种状态,但实际上只有九十多万。
    为什么呢?因为在 $0-9$ 中可以分为质数和合数($1$ 忽略):

    - $4,6,8,9$
    - $2,3,5,7$

    非质数可以看做是质数的乘积。那就可以看成由 $2357$ 这几个数字的乘积作为状态。而且 $2357$ 的最大个数可以找出来,就可以凑出好多状态。这些状态就最为 $dp$ 数组的第二维。

    然后按照数位 $dp$ 的套路做记忆化。要注意前导 $0$处理,前导 $0$ 如果放到乘积里会导致整个乘积都变为 $0$,所以要将前导状态的 $0$ 看做是 $1$。

    下面的代码只有90QAQ。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #define M 44800
    #define ll long long
    using namespace std;
    ll read() {
        ll nm = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
        return nm * f;
    }
    ll cnt = 0;
    ll poww2[100], poww3[100], poww5[100], poww7[101];
    ll dp[18][M];
    ll ff[18][M];
    int id[60][38][27][22];
    ll l, r, ln, rn;
    const ll up = 16677181699666568ll;
    int num[22];
    ll dfs(int len, bool f, bool qian,  int a, int b, int c, int d, ll now, ll upd, ll down) {
        if(id[a][b][c][d] == 0) return 0;
        if(len <= 0 )
            return (now >= down && now <= upd);
        if(!f && dp[len][id[a][b][c][d]] != -1 && !qian && now != 0) return dp[len][id[a][b][c][d]];
        if(!f && ff[len][id[a][b][c][d]] != -1 && !qian && now == 0) return ff[len][id[a][b][c][d]];
        ll ans = 0, top = (f ? num[len]:9);
        if(qian) {
            ans += dfs(len - 1,  f &&(num[len] == 0), true, a, b, c, d, now, upd, down);
        }
        else ans += dfs(len - 1, f &&(num[len] == 0), false, a, b, c, d, 0, upd, down);
        ll op = now;
        if(now == 0 && qian) now = 1;
        for(int i = 1; i <= top; i++) {
            if(i == 1) ans += dfs(len - 1, f &&(num[len] == i), false, a, b, c, d, now * i, upd, down);
            if(i == 2) ans += dfs(len - 1, f &&(num[len] == i), false, a + 1, b, c, d, now * i, upd, down);
            if(i == 3) ans += dfs(len - 1, f &&(num[len] == i), false, a, b + 1, c, d, now * i, upd, down);
            if(i == 4) ans += dfs(len - 1, f &&(num[len] == i), false, a + 2, b, c, d, now * i, upd, down);
            if(i == 5) ans += dfs(len - 1, f &&(num[len] == i), false, a, b, c + 1, d, now * i, upd, down);
            if(i == 6) ans += dfs(len - 1, f &&(num[len] == i), false, a + 1, b + 1, c, d, now * i, upd, down);
            if(i == 7) ans += dfs(len - 1, f &&(num[len] == i), false, a, b, c, d + 1, now * i, upd, down);
            if(i == 8) ans += dfs(len - 1, f &&(num[len] == i), false, a + 3, b, c, d, now * i, upd, down);
            if(i == 9) ans += dfs(len - 1, f &&(num[len] == i), false, a, b + 2, c, d, now * i, upd, down);
        }
        if(!f && !qian && now != 0) dp[len][id[a][b][c][d]] = ans;
        if(!f && !qian && now == 0) ff[len][id[a][b][c][d]] = ans;
        return ans;
    }
    ll solve(ll x, ll y, ll z) {
        ll xn = x;
        int tp = 0;
        if(x < 0) return 0;
        while(x) {
            num[++tp] = x % 10;
            x /= 10;
        }
        memset(dp, -1ll, sizeof(dp));
        ll as = dfs(tp, true, true, 0, 0, 0, 0, 0, y, z);
    //  cout << xn << " " << y << " " << as << "
    ";
        return as;
    }
    int main() {
        l = read(), r = read(), ln = read(), rn = read();
        poww2[0] = poww3[0] = poww5[0] = poww7[0] = 1;
        for(int i = 1; i <= 59; i++) {
            poww2[i] = poww2[i - 1] * 2;
            poww3[i] = poww3[i - 1] * 3;
            poww5[i] = poww5[i - 1] * 5;
            poww7[i] = poww7[i - 1] * 7;
        }
        for(int i = 0; i <= 59; i++) {
            ll now = poww2[i];
            if(now > up) break;
            for(int j = 0; j <= 37; j++) {
                ll a = now * poww3[j];
                if(a > up) break;
                for(int k = 0; k <= 26; k++) {
                    ll b = a * poww5[k];
                    if(b > up) break;
                    for(int l = 0; l <= 21; l++) {
                        ll c = b * poww7[l];
                        if(c > up) break;
                        id[i][j][k][l] = ++cnt;
                    }
                }
            }
        }
        cout << solve(r, rn, ln) - solve(l - 1, rn, ln)<< "
    ";
        return 0;
    }
  • 相关阅读:
    【BZOJ】1045: [HAOI2008]糖果传递(中位数)
    【BZOJ】1011: [HNOI2008]遥远的行星(近似)
    【BZOJ】1034: [ZJOI2008]泡泡堂BNB(贪心)
    【BZOJ】1029: [JSOI2007]建筑抢修(贪心)
    【BZOJ】1022: [SHOI2008]小约翰的游戏John(博弈论)
    【BZOJ】1010: [HNOI2008]玩具装箱toy(dp+斜率优化)
    noip2014滚粗记
    【NOIP模拟题】Permutation(dp+高精度)
    MySQL 关于自定义函数的操作
    MySQL 关于存储过程的操作
  • 原文地址:https://www.cnblogs.com/bljfy/p/9625476.html
Copyright © 2011-2022 走看看