• 2022牛客蔚来杯补题(第九场)


    A (签到)Car Show

    题意:在长度为n的数组(a[i]<=m)内,包括多少个区间[l,r]满足区间中包含1-m所有数

    题解:双指针

    code:

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N = 1e5 + 20;
    5. int n, m, a[N], cnt[N], sum;
    6. ll ans;
    7. int main(){
    8. scanf("%d%d", &n, &m);
    9. for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    10. for(int l = 1, r= 1; l <= n; l++){
    11. while(r <= n && sum < m){
    12. int res = a[r];
    13. if(!cnt[res]) sum++;
    14. cnt[res] ++;
    15. r++;
    16. }
    17. if(sum == m)
    18. ans += n - r + 2;
    19. cnt[a[l]]--;
    20. if(!cnt[a[l]]) sum--;
    21. }
    22. printf("%lld\n", ans);
    23. return 0;
    24. }

    B(DP)Two Frogs

    题意:有n块荷叶排成一排,从第i个荷叶起跳可以跳到[i + 1, i + a[i]]块荷叶(随机等概率),存在两只青蛙初始都在第一块荷叶,求两只青蛙以相同步数到达第n块荷叶的概率。

    题解:

            f[i][j]:跳跃i步到达j的概率

            方程:f[i][j + res] += f[i - 1][j] * \frac{1}{res}

            PS:如果正着推时间复杂度为O({n}^{3}),考虑处于当前状态对后面状态的影响(区间),可以用前缀和处理

    code:

    1. #include
    2. using namespace std;
    3. typedef long long ll;
    4. const int N = 8010;
    5. const int mod = 998244353;
    6. int n, a[N];
    7. ll f[N][N], b[N];
    8. ll ksm(ll a, ll b){
    9. ll res = 1;
    10. while(b){
    11. if(b & 1) res = res * a % mod;
    12. a = a * a % mod;
    13. b >>= 1;
    14. }
    15. return res;
    16. }
    17. int main(){
    18. scanf("%d", &n);
    19. for(int i = 1; i <= n; i++){
    20. scanf("%d", &a[i]);
    21. b[i] = ksm(a[i], mod - 2);
    22. }
    23. f[0][1] = 1;
    24. for(int i = 1; i < n; i++){ //跳跃i步
    25. for(int j = 1; j <= n; j++){ // 到达位置j
    26. int res = a[j];
    27. f[i][j + 1] = (f[i][j + 1] + f[i - 1][j] * b[j] + mod) % mod;
    28. f[i][j + res + 1] = (f[i][j + res + 1] - f[i - 1][j] * b[j] + mod) % mod;
    29. }
    30. for(int j = 1; j <= n; j++){
    31. f[i][j] = (f[i][j] + f[i][j - 1] + mod) % mod;
    32. }
    33. }
    34. ll ans = 0;
    35. for(int i = 1; i < n; i++){
    36. ans = (ans + f[i][n] * f[i][n] % mod + mod) % mod;
    37. }
    38. printf("%lld\n", ans);
    39. return 0;
    40. }

    C(树上差分 / 树链刨分)Global Positioning System

    D

    E(构造)Longest Increasing Subsequence

    题意:构造一个长度小于100的序列,使得序列中最长上升子序列恰好有m个

    题解:考虑两个数两个数为一组(例如: 2 1  4 3  6 5...),假设有x组,就会形成2^{x}个最长上升子序列,然后考虑在组与组之间插入数【将m拆成二进制】

    PS:插入的数也要发挥他的作用

    code:

    1. #include
    2. using namespace std;
    3. const int N = 110;
    4. int t, m;
    5. struct NODE{
    6. int id, x;
    7. }node[N];
    8. bool cmp(NODE a, NODE b){
    9. return a.x < b.x;
    10. }
    11. int main(){
    12. scanf("%d", &t);
    13. while(t--){
    14. scanf("%d", &m);
    15. if(m == 1){
    16. printf("1\n1\n");
    17. continue;
    18. }
    19. vector<int> ans;
    20. bitset<32> bit(m);
    21. int k = 31, res = 100;
    22. while(!bit[k]) k--;
    23. ans.push_back(2 * k - 1);
    24. ans.push_back(2 * k);
    25. int ned = 0, cnt = 0;
    26. while(--k >= 0){
    27. ned++;
    28. if(bit[k]){
    29. for(; cnt < ned; cnt++) ans.push_back(res), res--;
    30. }
    31. if(k){
    32. ans.push_back(2 * k - 1);
    33. ans.push_back(2 * k);
    34. }
    35. }
    36. reverse(ans.begin(), ans.end());
    37. int n = ans.size();
    38. printf("%d\n", n);
    39. for(int i = 0; i < n; i++){
    40. node[i].id = i;
    41. node[i].x = ans[i];
    42. }
    43. sort(node, node + n, cmp);
    44. for(int i = 0; i < n; i++){
    45. ans[node[i].id] = i + 1;
    46. }
    47. for(int i = 0; i < n; i++){
    48. printf("%d ", ans[i]);
    49. }
    50. puts("");
    51. }
    52. return 0;
    53. }

    F

    (队友补了等于我补了)

    G(SAM / Manache / PAM)Magic Spells

    题意:求k个串中的不同的公共回文串

    题解:解法有很多

    code:【队友打的】

    1. #include
    2. #define ll long long
    3. using namespace std;
    4. const int N = 3e5 + 50;
    5. struct node {
    6. int len, link, ch[26], id;
    7. }st[N << 1];
    8. int sz, last;
    9. void sam_init () { sz = last = 1; }
    10. void sam_extend (int c, int id) {
    11. int cur = ++ sz, p = last;
    12. st[cur].len = st[p].len + 1, last = cur;
    13. st[cur].id = id;
    14. for ( ; p && ! st[p].ch[c]; p = st[p].link) st[p].ch[c] = cur;
    15. if (! p) st[cur].link = 1;
    16. else {
    17. int q = st[p].ch[c];
    18. if (st[p].len + 1 == st[q].len) st[cur].link = q;
    19. else {
    20. int clone = ++ sz;
    21. st[clone].len = st[p].len + 1;
    22. st[clone].link = st[q].link;
    23. st[clone].id = st[q].id;
    24. memcpy (st[clone].ch, st[q].ch, sizeof (st[q].ch));
    25. for ( ; p && st[p].ch[c] == q; p = st[p].link) st[p].ch[c] = clone;
    26. st[q].link = st[cur].link = clone;
    27. }
    28. }
    29. }
    30. char s[5][N], str[N << 1];
    31. int a[N << 1], b[N], n, k;
    32. int g[N << 1], f[N << 1];
    33. int p[N << 2], lef[N << 1];
    34. void manacher (char* s, int len) {
    35. for (int i = 1, r = 0, mid = 0; i < len; i ++) {
    36. if (i <= r) p[i] = min (p[(mid << 1) - i], r - i + 1);
    37. while (s[i - p[i]] == s[i + p[i]]) ++ p[i];
    38. if (p[i] + i > r) r = p[i] + i - 1, mid = i;
    39. }
    40. }
    41. bool vis[N << 1];
    42. void solve () {
    43. str[0] = '~', str[1] = '|';
    44. int len = 1;
    45. for (int i = 0; i < n; i ++)
    46. str[++ len] = s[0][i], str[++ len] = '|';
    47. manacher (str, len);
    48. // printf("%s\n", str);
    49. for (int i = 1; i <= n; i ++) lef[i] = i;
    50. for (int i = 2; i < len; i ++) {
    51. // printf("i = %d, p = %d\n", i / 2, p[i] - 1);
    52. lef[(i + p[i]) / 2 - 1] = min (lef[(i + p[i]) / 2 - 1], (i - p[i]) / 2 + 1);
    53. }
    54. for (int i = n; i >= 2; i --) lef[i - 1] = min (lef[i - 1], lef[i] + 1);
    55. // for (int i = 1; i <= n; i ++)
    56. // printf("lef = %d\n", lef[i]);
    57. ll ans = 0;
    58. for (int i = 1; i <= sz; i ++) {
    59. int x = st[i].id - g[i] + 1, y = st[i].id;
    60. if (x <= y) {
    61. if (vis[st[i].id]) continue;
    62. int nx = lef[st[i].id], ny = st[i].id;
    63. if (x <= nx && (ny - nx + 1 > st[st[i].link].len)) {
    64. ans ++;
    65. vis[st[i].id] = true;
    66. }
    67. // printf("len = %d\n", st[st[i].link].len);
    68. // printf("i = %d, x = %d, y = %d, nx = %d, ny = %d\n", st[i].id, x, y, nx, ny);
    69. }
    70. }
    71. printf("%lld\n", ans);
    72. }
    73. int main () {
    74. // freopen("in.txt", "r", stdin);
    75. // freopen("test.txt", "w", stdout);
    76. scanf ("%d%s", &k, s[0]);
    77. sam_init ();
    78. n = strlen (s[0]);
    79. for (int i = 0; i < n; i ++) sam_extend (s[0][i] - 'a', i + 1);
    80. for (int i = 1; i <= sz; i ++) b[st[i].len] ++;
    81. for (int i = 1; i <= n; i ++) b[i] += b[i - 1];
    82. for (int i = sz; i >= 1; i --) a[b[st[i].len] --] = i;
    83. for (int i = 1; i <= sz; i ++) g[i] = st[i].len;
    84. for (int j = 1; j < k; j ++) {
    85. scanf ("%s", s[j]);
    86. for (int i = 1; i <= sz; i ++) f[i] = 0;
    87. for (int i = 0, v = 1, len = 0; s[j][i]; i ++) {
    88. int c = s[j][i] - 'a';
    89. while (v && ! st[v].ch[c]) v = st[v].link, len = st[v].len;
    90. if (! v) v = 1, len = 0;
    91. if (st[v].ch[c]) ++ len, v = st[v].ch[c]; // 匹配成功,那么匹配出去即可。
    92. f[v] = max (f[v], len); // 更新该结点的长度
    93. }
    94. for (int i = sz; i >= 1; i --)
    95. f[st[a[i]].link] = max (f[st[a[i]].link], f[a[i]]);
    96. for (int i = 1; i <= sz; i ++) g[i] = min (f[i], g[i]);
    97. }
    98. // printf("%d\n", *max_element(g + 1, g + sz + 1));
    99. // for (int i = 1; i <= sz; i ++) {
    100. // printf("i = %d, len = %d\n", st[i].id, g[i]);
    101. // }
    102. solve ();
    103. return 0;
    104. }

    H

    I(dp 单调栈优化)The Great Wall II

    题意:一个长的为n的数组分成k段,求每一段的最大值之和最小

    题解:dp[i][j] : 前i个数分成j段的最小值

            dp[i][j] = min\left \{ dp[k][j - 1] + max(a[k + 1] ~ a[i]) \right \}

    code:

    1. #include
    2. using namespace std;
    3. const int N = 8010;
    4. const int INF = 0x3f3f3f3f;
    5. int n, a[N], dp[N][2];
    6. struct NODE{
    7. int x, f, minn;
    8. };
    9. int main(){
    10. scanf("%d", &n);
    11. for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    12. for(int i = 1; i <= n; i++){
    13. dp[i][1] = max(dp[i - 1][1], a[i]);
    14. }
    15. printf("%d\n", dp[n][1]);
    16. for(int j = 2; j <= n; j ++){
    17. stack st;
    18. for(int i = 1; i <= n; i++){
    19. dp[i][j & 1] = 0;
    20. }
    21. for(int i = 1; i <= n; i++){
    22. if(i < j){
    23. dp[i][j & 1] = dp[i][(j - 1) & 1];
    24. continue;
    25. }
    26. if(st.size() && a[i] >= st.top().x){ // 弹出
    27. int dpmin = dp[i - 1][(j - 1) & 1];
    28. while(st.size() && a[i] >= st.top().x){
    29. NODE res = st.top();
    30. st.pop();
    31. dpmin = min(dpmin, res.f);
    32. }
    33. dp[i][j & 1] = a[i] + dpmin;
    34. if(st.size()){
    35. dp[i][j & 1] = min(st.top().minn, dp[i][j & 1]);
    36. }
    37. st.push({a[i], dpmin, dp[i][j & 1]});
    38. }
    39. else{
    40. dp[i][j & 1] = a[i] + dp[i - 1][(j - 1) & 1];
    41. if(st.size()){
    42. dp[i][j & 1] = min(st.top().minn, dp[i][j & 1]);
    43. }
    44. st.push({a[i], dp[i - 1][(j - 1) & 1], dp[i][j & 1]});
    45. }
    46. }
    47. printf("%d\n", dp[n][j & 1]);
    48. }
    49. return 0;
    50. }

    J

    K

  • 相关阅读:
    【DPDK】使用 Open vSwitch * 采用 DPDK 帧间 VM NFV 应用程序
    git命令合并某一个分支的某个commit到目标分支
    Spring学习之ImportBeanDefinitionRegistrar接口
    C++ 嵌套 switch 语句
    钟汉良日记:出门在外靠什么?
    对Redis布隆过滤器的实现
    【无标题】
    微服务_fegin
    2023年天津财经大学珠江学院专升本管理学原理专业考试大纲
    论文阅读: Disentangled lmage Colorization via Global Anchors
  • 原文地址:https://blog.csdn.net/Galaxy_Su/article/details/126725548