2019暑训 第一场训练赛 (2016-icpc区域赛)题解

 // 今天下午比赛自闭了,晚上补了题,把AC的部分水题整理一下,记录坑点并吸取教训。

 // CF补题链接:http://codeforces.com/gym/101291

A - Alphabet

题目大意:

    给定一字符串,问至少需要添加多少字母后,能使该字符串删掉一些字母后成为“abcdefghijklmnopqrstuvwxyz"的序列。

分析及代码:

    最长上升子序列(LIS)问题,n的规模不大,直接DP两重循环求解。答案为 26-最长上升子序列的长度。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int main() {
    char str[100];
    int dp[100];      // dp[i] 以str[i]结尾的最长上升子序列的长度
                          // dp[i] = max(dp[i], dp[k]+1), 0<=k<i, str[k]<str[i]
    int maxLen = 0;   // maxLen = max(dp[i]), 0<=i<n
    scanf("%s", str);
    int len = strlen(str);
    for(int i=0;i<len;i++) {
        dp[i] = 1;
        for(int j=0;j<i;j++) {
            if(str[j]<str[i]) {
               dp[i] = max(dp[i], dp[j]+1);
            }
        }
        maxLen = max(maxLen, dp[i]);
    }
    
    printf("%d\n", 26-maxLen);

    return 0;
}
View Code

    顺便学习了求解最长公共子序列(LCS)与LIS的O(nlogn)算法,其利用了贪心思想和二分搜索。

    数组dp表示目前找到的最长序列,不影响dp长度前提下,在原序列中尽可能找到更小的元素来代替现有的最长序列中的元素;如果比最大的元素要大,就添加在dp末尾。

    由于数组dp单调,使用二分搜索能将更新的复杂度降低到O(logn),所以总的复杂度为O(nlogn)。

// 返回最长上升子序列的长度
// 时间复杂度: O(nlogn)
// 来源:https://blog.csdn.net/ltrbless/article/details/81318935 
//
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    char arr[100],  dp[100];
    scanf("%s", arr);
    int n = strlen(arr);

    /* 求解最长子序列的个数的核心代码 */
    /* ********************************************** */
    int k = 1;
    dp[k] = arr[0];
    for(int i=1;i<n;i++) {
        if(dp[k]<arr[i]) dp[++k] = arr[i];              //如果比最后一个元素大,那么就添加再最后末尾处
        else *(lower_bound(dp, dp+k, arr[i])) = arr[i]; //如果比最后一个元素小,那么就替换该序列第一个比他大的数;
    }
    /* ********************************************** */
 
    printf("最长子序列的个数为: %d\n", k);
    return 0;

}
View Code

B - Barbells

F - Equality 

G - Gravity

H - Islands

J - Postman

K - Six Sides

猜你喜欢

转载自www.cnblogs.com/izcat/p/11141307.html