zoukankan      html  css  js  c++  java
  • everyday two problems / 3.1

    T1.string

    题意:

    给定由小写字母组成的长度为 n 的字符串

    将其所有 n * (n + 1) / 2 个子串按字典序排序

    输出第 k 个子串

    k > (n * (n + 1) / 2) 就输出"No such line."

    1 <= n, k <= 1e5

    解法:

    解法很多(我不会写自动机啊

    我用的解法应该算是比较简单

    一位一位地去计数来确定当前位的字母

    比如一开始O(n)扫描出以a开头的子串有3个

    以b开头的子串有4个,而我要输出排名第5的子串

    所以这一位一定是'b',后面每一位字母的确定同理

    当前位是空格的时候标志着结果输出结束

    代码比较简单,可以参考

    但是我们要说明一下效率

    一开始脑残了误以为是O(26n)

    但是其实每次while中运行次数与之前已经输出的子串在原字符串中出现的次数有关

    那么我们可以考虑最坏情况,10w个'a'

    这时候如果要求输出排名最靠后的子串的话效率已经O(n^2)

    还好我们题目有限制 k <= 1e5

    所以这种做法的最坏效率其实比较玄学(但是过了就好了233

     1 #include <cstdio>
     2 #include <vector>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 
     7 typedef long long ll;
     8 
     9 vector <int> p[27], pp;
    10 
    11 char str[100010];
    12 
    13 ll cnt[27];
    14 
    15 int n, m;
    16 
    17 int main() {
    18     scanf("%s %d", str, &m);
    19     n = strlen(str);
    20     if(1ll * n * (n + 1) / 2 < m) {
    21         puts("No such line.");
    22         return 0;
    23     }
    24     for(int j, i = 0;i < n;i ++) {
    25         j = str[i] - 96;
    26         cnt[j] += n - i;
    27         p[j].push_back(i);
    28     }
    29     while(1) {
    30         int pos;
    31         for(int i = 0;i <= 26;i ++) {
    32             if(cnt[i] >= m) {
    33                 pos = i;
    34                 if(!pos) return 0;
    35                 putchar(96 + i);
    36                 break;
    37             }
    38             else m -= cnt[i];
    39         }
    40         for(int i = 1;i <= 26;i ++) {
    41             cnt[i] = 0;
    42             if(i != pos) p[i].clear();
    43         }
    44         cnt[0] = p[pos].size();
    45         for(int k, j, i = 0;i < p[pos].size();i ++) {
    46             j = p[pos][i] + 1;
    47             if(j >= n) continue;
    48             k = str[j] - 96;
    49             cnt[k] += n - j;
    50             if(k == pos) pp.push_back(j);
    51             else p[k].push_back(j);
    52         }
    53         p[pos].clear();
    54         for(int i = 0;i < pp.size();i ++)
    55             p[pos].push_back(pp[i]);
    56         pp.clear();
    57     }
    58 }
    View Code

    T2.Levko and Array

     

    题意:

    给定数组a[2000],-1e9 <= a[i] <= 1e9

    最多允许修改 k(k <= n) 个元素

    求 max(abs(a[i] - a[i + 1])) 的最小值 

    解法:

    这题是看别人题解做的

    猜测正解效率可能n^2

    但并没有什么策略能直接由条件得到答案

    满足单调,考虑二分,可能效率n^2logn,可以接受

    然后这个judge函数就比较神了

    考虑dp,f[i]表示先只考虑前 i 个且第 i 个不动的情况下

    最少修改多少个能够让前 i 个的 max(abs(a[i] - a[i + 1])) <= mid

    转移方程 f[i] = min(f[i], f[j] + i - j - 1)

    转移条件是abs(f[i] - f[j]) <= (i - j) * mid

    即,保证i j 都不变,(i, j)都改变

    要能够使[i, j]任意相邻两个之差 <= mid才能转移

    上面我们提到f[i]的意义,只考虑了前 i 个

    但我们考虑最优解一定有最后连续 t 个都是要被修改的(0 <= t < n)

    所以我们计算完所有 f[i] 之后

    在从 1 到 n 扫一遍 f[i] + n - i

    是一定能够包含最优解的

    当然f[i] + n - i <= k就可以返回true了

    参考的题解

     1 #include <cstdio>
     2 
     3 typedef long long ll; 
     4 
     5 int n, k, a[2010], f[2010];
     6 
     7 int min(int x, int y) {
     8     return x < y ? x : y;
     9 }
    10 
    11 int dis(int x, int y) {
    12     if(x < y) return y - x;
    13     return x - y;
    14 }
    15 
    16 bool judge(ll d) {
    17     f[1] = 0;
    18     for(int i = 2;i <= n;i ++) {
    19         f[i] = 66666;
    20         for(int j = i- 1;j;j --) 
    21             if(dis(a[i], a[j]) <= d * (i - j))
    22                 f[i] = min(f[i], f[j] + i - j - 1);
    23         if(i <= k + 1) f[i] = min(f[i], i - 1);
    24     }
    25     for(int i = 1;i <= n;i ++)
    26         if(f[i] + n - i <= k)
    27             return 1;
    28     return 0;
    29 }
    30 
    31 int main() {
    32     scanf("%d %d", &n, &k);
    33     for(int i = 1;i <= n;i ++) 
    34         scanf("%d", &a[i]);
    35     ll l = 0, r = 2e9, mid;
    36     while(l <= r) {
    37         mid = (l + r) >> 1;
    38         if(judge(mid)) r = mid - 1;
    39         else l = mid + 1;
    40     }
    41     printf("%I64d", l);
    42     return 0;
    43 }
    View Code
  • 相关阅读:
    HackerRank
    HackerRank
    LeetCode "Kth Smallest Element in a BST"
    HackerRank
    HackerRank
    LeetCode "Roman to Integer"
    LeetCode "Integer to Roman"
    LeetCode "Majority Element II"
    HackerRank
    HackerRank
  • 原文地址:https://www.cnblogs.com/ytytzzz/p/6498597.html
Copyright © 2011-2022 走看看