# 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; }