codeforces 1183H 动态规划

codeforces 1183H 动态规划

传送门:https://codeforces.com/contest/1183/problem/H

题意:

给你一串长度为n的字符串,你需要寻找出他的最长的前k个子串,问你得到这些子串需要减少的字符个数之和是多少,easy版本的k是100,hard版本的k是1e12。

题解:

hard版本题解:

dp[i][j]表示前i个字符中选择了j个的子串数目

如果前面有出现过的字符呢?比如 aba 算到第二个a的时候 把ab 删掉 和 把 ba删掉 得到同一种结果

因此,对于XYYX 这种形式的我们把第一个X之前出现过的种数去掉,就可以避免多算的情况了

这里我们用一个pre数组来记录第一个X出现的位置

代码:

#include <set>
#include <map>
#include <cmath>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
LL dp[1005][1005];
char a[maxn];
int pre[1005];
int main() {
#ifndef ONLINE_JUDGE
    FIN
#endif
    IO;
    int n;
    LL k;
    scanf("%d%lld%s", &n, &k, a + 1);
    dp[0][0] = 1;
    for(int i = 1; i <= n; i++) {
        dp[i][0] = 1;
        for(int j = 1; j <= i; j++) {
            dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]);
            if(pre[a[i] - 'a']) dp[i][j] -= dp[pre[a[i] - 'a'] - 1][j - 1];
            if(dp[i][j] > k) dp[i][j] = k;
        }
        pre[a[i] - 'a'] = i;
    }
    LL ans = 0;
    for(int i = n; i >= 0; i--) {
        ans += min(dp[n][i], k) * (n - i);
        k -= dp[n][i];
        if(k <= 0) break;
    }
    if(k > 0) printf("-1\n");
    else printf("%lld\n", ans);
    return 0;
}
高效学习动态规划(Dynamic Programming, DP)是一项需要系统性和实践相结合的过程。以下是关于如何高效学习动态规划的最佳实践、教程和技巧的详细介绍: ### 1. 理解动态规划的核心概念 动态规划是一种通过将复杂问题分解为更小子问题的方式来解决问题的技术。它的两个主要特性是 **最优子结构** 和 **重叠子问题**。理解这些特性对于掌握动态规划至关重要[^4]。 - **最优子结构**: 如果一个问题的最优解可以通过其子问题的最优解构建出来,则该问题具有最优子结构性质。 - **重叠子问题**: 子问题是重复出现的,这意味着我们可以存储之前的结果以避免冗余计算。 ### 2. 学习经典的动态规划问题 熟悉一些经典的问题可以帮助建立对动态规划的理解。这些问题包括但不限于: - 背包问题(Knapsack Problem- 最长公共子序列(Longest Common Subsequence, LCS) - 编辑距离(Edit Distance) 每种问题都有其独特的状态转移方程和边界条件,深入研究它们有助于形成清晰的思维模型[^2]。 ```python def lcs(X , Y): m = len(X) n = len(Y) L = [[None]*(n + 1) for i in range(m + 1)] for i in range(m + 1): for j in range(n + 1): if i == 0 or j == 0 : L[i][j] = 0 elif X[i-1] == Y[j-1]: L[i][j] = L[i-1][j-1]+1 else: L[i][j] = max(L[i-1][j], L[i][j-1]) return L[m][n] ``` 此代码展示了最长公共子序列的一个实现方式。 ### 3. 使用合适的工具和资源 选择适合自己的学习材料非常重要。以下是一些推荐的学习资源: - **书籍**: *Introduction to Algorithms* by Thomas H. Cormen et al. - **在线课程**: Coursera上的Algorithms Specialization提供了详细的讲解。 - **练习平台**: LeetCode、Codeforces等网站上有丰富的DP题目供练习[^4]。 ### 4. 实践与反思 不断实践并通过解决新问题来巩固所学知识。每次完成一道题后,尝试总结其中的状态定义、转移方程以及初始化过程,并思考是否有其他变体或改进空间[^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值