[关闭]
@2368860385 2020-11-07T03:03:23.000000Z 字数 4692 阅读 999

nowcoder_第一场

比赛总结


考试总结:
打的不行,没有全力去想每一个部分分,没有拼命去打。T2思路没有扩展开。
T2想到了f[i][j]为第i位,乘积为j的dp,然后发现空间会炸,之后发现所有乘积是2,3,5,7的幂相乘,然后感觉可以枚举,于是想枚举一个乘积,看有多少数在LR之间。其实发现乘积很少,直接压一下状态就行了,甚至可以写20个map的。。。。
T1没想出正解,然后就几乎放弃了,想写60分,然后写了...还以为是


T1

二分一个中位数并不具有单调性。可能1可以是中位数,2就不行了,3又可以了。
二分一个区间[x,+oo),这是具有单调性的。
比如:
第一个是 101000100
第二个是 111111100
位置代表这个数字,1代表是与否。

二分很奇妙!!!

对于数字的不同的个数很少的情况:枚举一个中位数,小于的设为-1,大于等于的设为1,如果存在一个长度大于等于m的区间,那么说明存在一个中位数大于等于x。
于是可以二分这个x。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. using namespace std;
  7. typedef long long LL;
  8. inline int read() {
  9. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  10. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  11. }
  12. const int N = 100100;
  13. int a[N], b[N], n, L;
  14. bool check(int x) {
  15. for (int i=1; i<=n; ++i) b[i] = a[i] >= x ? 1 : -1;
  16. for (int i=1,Mi= 1e9; i<=n; ++i) {
  17. if (i > L) Mi = min(Mi, b[i - L]);
  18. b[i] += b[i - 1];
  19. if (i > L && b[i] - Mi > 0) return true;
  20. }
  21. return false;
  22. }
  23. int main() {
  24. n = read(), L = read();
  25. for (int i=1; i<=n; ++i) a[i] = read();
  26. int l = 0, r = 1e9, ans;
  27. while (l <= r) {
  28. int mid = (l + r) >> 1;
  29. if (check(mid)) ans = mid, l = mid + 1;
  30. else r = mid - 1;
  31. }
  32. cout << ans;
  33. return 0;
  34. }

T2

乘积(第二维)状态都是的形式,于是状态数并不多,对每个状态编一个号,然后dp。
或者直接 map< LL, LL >dp[22]。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  7. #include<set>
  8. #include<vector>
  9. #include<queue>
  10. #include<map>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  15. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  16. }
  17. const int N = 500100;
  18. map<LL,int> mp;
  19. LL f[22][N];
  20. int num[22];
  21. LL L, R, L1, R1;
  22. int Index;
  23. LL dfs(int p,LL sum,bool Head,bool lim) {
  24. if (p == 0) {
  25. if (sum >= L1 && sum <= R1) return 1;
  26. return 0;
  27. }
  28. int id = mp[sum];
  29. if (Head && !lim && f[p][id] != -1) return f[p][id];
  30. int u = lim ? num[p] : 9;
  31. LL res = 0;
  32. for (int i=0; i<=u; ++i) {
  33. if (i == 0) res += dfs(p - 1, Head?0:1, Head, lim&&i==num[p]);
  34. else res += dfs(p - 1, sum * i, 1, lim&&i==num[p]);
  35. // 如果sum * i大于R1了,不能直接跳过,因为后面还可能有0
  36. }
  37. if (Head && !lim) f[p][id] = res;
  38. return res;
  39. }
  40. LL solve(LL x) {
  41. if (x < 0) return 0;
  42. if (x == 0 && x >= L1 && x <= R1) return 1;
  43. int p = 0;
  44. while (x) {
  45. num[++p] = x % 10;
  46. x /= 10;
  47. }
  48. return dfs(p, 1, 0, 1);
  49. }
  50. int pri[] = {2, 3, 5, 7};
  51. void getsta(int x, LL sum) {
  52. if (x == 4) {
  53. mp[sum] = ++Index;
  54. return ;
  55. }
  56. getsta(x + 1, sum);
  57. for (int i=1; (sum*=pri[x])<=R1; ++i)
  58. getsta(x + 1, sum);
  59. }
  60. int main() {
  61. memset(f, -1, sizeof(f));
  62. cin >> L >> R >> L1 >> R1;
  63. mp[0] = ++Index;
  64. getsta(0, 1ll);
  65. cout << solve(R) - solve(L - 1);
  66. return 0;
  67. }

T3

题意:一棵树,很多条路径,每次询问(v,k)为:在v到1的路径上,寻找距离1最近的一个点u,使得这个v->u的路径被k条给出的路径完全覆盖。
一条路径覆盖另一条路径必须是被覆盖的,完全在另一条中。

暴力就是,枚举一个在v->1的路径上枚举一个u,然后判断所有的路径是否能覆盖v->u。
优化:对于查询的一条路径(u,p),相当于查询有多少条给定的路径(x,y),满足x在u子树,y在p子树外部,反过来也可以。
那么可以讲一条给定的路径(x,y)拆成(x,lca),(y,lca),就是说,x,y的子树中有一条路径的一个端点在子树内,另一个端点在LCA,那么这条路径的贡献就是deth[lca],于是在x,y出打上一个标记为deth[lca]。

现在查询v,就是在v的子树内查询第k小的数。

对每个点建立主席树,然后可以快速插叙。由于有些父节点是有子节点的信息的,于是启发式合并维护。

然后发现如果转化为dfs序上,就是查询一段区间的k小值。又出现了一个问题:就是每个点不止插入一个标记,那么就暴力插入吧,依次在主席树的序列上排开,Root[i]就是i的所有标记插入完后的位置。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  7. #include<set>
  8. #include<vector>
  9. #include<queue>
  10. #include<map>
  11. using namespace std;
  12. typedef long long LL;
  13. inline int read() {
  14. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  15. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  16. }
  17. const int N = 200005;
  18. int L[N], R[N], pos[N], deth[N], f[N][21];
  19. int ls[N * 40], rs[N * 40], sum[N * 40], Root[N];
  20. int Time_Index, CntNode;
  21. vector<int> T[N];
  22. vector<int> tag[N];
  23. void dfs(int u,int fa) {
  24. f[u][0] = fa;
  25. deth[u] = deth[fa] + 1;
  26. L[u] = ++Time_Index;
  27. pos[Time_Index] = u;
  28. for (int sz=T[u].size(),i=0; i<sz; ++i) {
  29. int v = T[u][i];
  30. if (v == fa) continue;
  31. dfs(v, u);
  32. }
  33. R[u] = Time_Index;
  34. }
  35. int LCA(int u,int v) {
  36. if (deth[u] < deth[v]) swap(u, v);
  37. int d = deth[u] - deth[v];
  38. for (int j=20; j>=0; --j)
  39. if ((1 << j) & d) u = f[u][j];
  40. if (u == v) return u;
  41. for (int j=20; j>=0; --j)
  42. if (f[u][j] != f[v][j])
  43. u = f[u][j], v = f[v][j];
  44. return f[u][0];
  45. }
  46. void update(int l,int r,int &rt,int last,int p) {
  47. rt = ++CntNode;
  48. ls[rt] = ls[last], rs[rt] = rs[last], sum[rt] = sum[last] + 1;
  49. if (l == r) return ;
  50. int mid = (l + r) >> 1;
  51. if (p <= mid) update(l, mid, ls[rt], ls[last], p);
  52. else update(mid + 1, r, rs[rt], rs[last], p);
  53. }
  54. int query(int l,int r,int Head,int Tail,int k) {
  55. if (sum[Tail] - sum[Head] < k) return -1;
  56. if (l == r) return l;
  57. int cnt = sum[ls[Tail]] - sum[ls[Head]];
  58. int mid = (l + r) >> 1;
  59. if (k <= cnt) return query(l, mid, ls[Head], ls[Tail], k);
  60. else return query(mid + 1, r, rs[Head], rs[Tail], k - cnt);
  61. }
  62. int main() {
  63. int n = read(), m = read();
  64. for (int i=1; i<n; ++i) {
  65. int u = read(), v = read();
  66. T[u].push_back(v), T[v].push_back(u);
  67. }
  68. dfs(1, 0);
  69. for (int j=1; j<=20; ++j)
  70. for (int i=1; i<=n; ++i)
  71. f[i][j] = f[f[i][j - 1]][j - 1];
  72. for (int i=1; i<=m; ++i) {
  73. int u = read(), v = read(), lca = LCA(u, v);
  74. tag[u].push_back(deth[lca]), tag[v].push_back(deth[lca]);
  75. }
  76. for (int i=1; i<=n; ++i) {
  77. Root[i] = Root[i - 1]; // 没有也要赋一个值!!!
  78. int last = Root[i - 1];
  79. for (int sz=tag[pos[i]].size(),j=0; j<sz; ++j) {
  80. update(1, n, Root[i], last, tag[pos[i]][j]);
  81. last = Root[i];
  82. }
  83. }
  84. int Q = read();
  85. while (Q--) {
  86. int v = read(), k = read();
  87. int t = query(1, n, Root[L[v] - 1], Root[R[v]], k);
  88. if (t == -1 || t >= deth[v]) puts("0");
  89. else printf("%d\n", deth[v] - t);
  90. }
  91. return 0;
  92. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注