• [Offer收割]编程练习赛10简略题解


    题目1 : 出勤记录I(水题)

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    小Hi的算法课老师每次上课都会统计小Hi的出勤记录。迟到会被记录一个L,缺席会被记录一个A,按时上课会被记录一个O。

    一学期结束,小Hi的出勤记录可以看成是一个只包含LAO的字符串,例如"OOOOLOOOLALLO……"。

    如果小Hi整学期缺席不超过1次,并且没有连续3次迟到,小Hi的出勤记录就算合格。  

    现在给出小Hi的出勤记录,你能判断他是否合格么?

    输入

    输入第一行包含一个整数T(1 <= T <= 10),代表测试数据的组数。  

    以下T行每行一个程度不超过100的字符串S,代表小Hi的出勤记录。

    输出

    对于每一份出勤记录,输出YES或者NO表示该份记录是否合格。

    样例输入
    3
    LLOLLALL  
    OLLLOOOO  
    OOAAOOOO
    样例输出
    YES  
    NO  
    NO
    判断是否有“LLL”出现或者"A"出现的个数超过两次 输出NO,其他为YES

    题目2 : 出勤记录II(dp)

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    小Hi的算法课老师每次上课都会统计小Hi的出勤记录。迟到会被记录一个L,缺席会被记录一个A,按时上课会被记录一个O。

    一学期结束,小Hi的出勤记录可以看成是一个只包含LAO的字符串,例如"OOOOLOOOLALLO……"。

    如果小Hi整学期缺席不超过1次,并且没有连续3次迟到,小Hi的出勤记录就算合格。  

    现在给出字符串的长度N,小Hi想知道长度为N的出勤记录中,合格的记录总共有多少种。  

    例如长度为3的合格出勤记录有19种:OOO OOL OOA OLO OAO LOO AOO OLL OLA OAL LOL LOA AOL LLO LAO ALO LLA LAL ALL。

    输入

    一个整数N(1 <= N <= 100000)。

    输出

    长度为N的合格记录总数。由于结果可能很大,你只需输出结果模109+7的余数。

    样例输入
    3

    样例输出
    19
    可以用dp[i][A][L]表示长度为N序列的串,“A”出现的个数为A, 末尾连续“L”的个数为L个
    if(s[i+1] == 'L' && L <= 2 && L >= 1) dp[i+1][A][L] += dp[i][A][L-1]
    if( s[i+1] == 'A') dp[i+1][1][0] += dp[i][0][L]
    if( s[i+1] == 'O') dp[i+1][A][0] += dp[i][A][L]
    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <map>
    
    using namespace std;
    const int MAXN = 2e5+10;
    int A[MAXN], cnt[MAXN];
    int n;
    typedef long long int LL;
    LL k;
    map<int, int>Map;
    LL slove(LL ans){
        LL ret = 0, sum = 0;
        for(int i = 0, j = 0; i < n; i++){
            while(j < n && sum+cnt[A[j]] <= ans)    {
                sum += cnt[A[j]];
                cnt[A[j]]++;
                j++;
            }
            ret += j-i;
            cnt[A[i]]--;
            sum -= cnt[A[i]];
        }
        return ret;
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &k);
            for(int i = 0; i < n; i++){
                scanf("%d", &A[i]);
                Map[A[i]] = i;
            }
            for(int i = 0; i < n; i++) A[i] = Map[A[i]];
            LL L = -1, R = 1LL*n*(n+1);
            while(L + 1 < R){
                LL mid = (L+R)>>1;
                if(slove(mid) < k) L = mid;
                else R = mid;
            }
            printf("%lld
    ", R);
        }
        return 0;
    }

    题目3 : 区间价值(二分+双指针)

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    给定n个数A1...An,小Ho想了解AL..AR中有多少对元素值相同。小Ho把这个数目定义为区间[L,R]的价值,用v[L,R]表示。

    例如1 1 1 2 2这五个数所组成的区间的价值为4。

    现在小Ho想知道在所有的的v[L,R](1 <= L <= R <= n)中,第k小的值是多少。

    输入

    第一行一个数T(T<=10),表示数据组数。

    对于每一组数据:

    第一行两个数n,k(1<=n<=200,000,1<=k<=n*(n+1)/2)

    第二行n个数A1…An(1<=Ai<=1,000,000,000)

    输出

    一个数表示答案。

    样例输入
    2
    4 7
    1 1 2 3
    3 6
    100 100 100
    样例输出
    0
    3


    二分答案,用双指针求出[1~n]区间 <= ans的个数

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <map>
    
    using namespace std;
    const int MAXN = 2e5+10;
    int A[MAXN], cnt[MAXN];
    int n;
    typedef long long int LL;
    LL k;
    map<int, int>Map;
    LL slove(LL ans){
        LL ret = 0, sum = 0;
        //ret 小于等于ans区间的个数
        for(int i = 0, j = 0; i < n; i++){
            while(j < n && sum+cnt[A[j]] <= ans)    {
                sum += cnt[A[j]];
                cnt[A[j]]++;
                j++;//指针j向右移动
            }
            ret += j-i;//求出满足条件区间的 个数  
            cnt[A[i]]--;//指针i向右移动
            sum -= cnt[A[i]];
        }
        return ret;
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &k);
            for(int i = 0; i < n; i++){
                scanf("%d", &A[i]);
                Map[A[i]] = i;
            }
            for(int i = 0; i < n; i++) A[i] = Map[A[i]];//使A[i]处在[0~n-1]
            LL L = -1, R = 1LL*n*(n+1);
            while(L + 1 < R){
                LL mid = (L+R)>>1;
                if(slove(mid) < k) L = mid;
                else R = mid;
            }
            printf("%lld
    ", R);
        }
        return 0;
    }
    
    
  • 相关阅读:
    docker 介绍,安装,镜像操作, docker换源
    go语言5 接口, 并发与并行, go协程, 信道, 缓冲信道, 异常处理, python进程线程
    [编织消息框架]目录
    2017总结
    赚钱方法[信息红利]
    面单 全单 单板 批发吉他民谣 知乎 百度知道 百度贴吧 吉他批发
    看第三部杀破狼感想
    海豚极货店 淘宝店开张啦
    我上头条了
    尤克里里 ukulele 单板 非kaka tom uma
  • 原文地址:https://www.cnblogs.com/cshg/p/6582483.html
Copyright © 2020-2023  润新知