牛客网 nowcoder TG test-172

# solution-nowcoder-172


# A-中位数


 

  • $30\%:n\le 200$
    • 直接枚举 $n-len+1$ 个区间,将这段里的数重新排序直接找到中位数

 

  • $60\%:n\le 2000$
    • 用主席树维护,查询区间第 $k$ 小。时间复杂度是 $\Theta(n^2\log ^2n)$,我只过了 $50$ 分。应该是用平衡树维护,时间复杂度是$\Theta(n^2\log n)

 

  • $100\%:n\le 10^5$
    • 前缀和 $+$ 前缀最小值 $+$ 二分答案。二分一个 $mid$,判断一下行不行,如何判断?在长度为 $n$ 的序列中,用一个b数组记录一下,$a[i]>mid\rightarrow b[i]=1,a[i]<=mid\rightarrow 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 << "\n";
    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)<< "\n";
    return 0;
}

 

posted @ 2018-09-11 08:42  Mystical-W  阅读(154)  评论(0编辑  收藏  举报