HZAUoj 1015: LCS 【LCS变形】 + 1016: Array C 【贪心】

这篇博客介绍了如何解决两道编程题目:HZAUoj 1015 - LCS 的特殊情况,通过优化动态规划实现O(n^2)的时间复杂度;以及HZAUoj 1016 - Array C,利用贪心策略求解最小的平方和。博主分享了关键思路和AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨天真是SB,20多个人花了6个小时顶着太阳去爬山,结果为了赶车还没到顶,真心不如在机房打代码。

题目链接:HZAUoj 1015: LCS
题意:给定两个字符串a和b,让你找它们特殊的LCS——该LCS在a、b原串中任一连续段长度不小于k。问你最长的LCS。
思路:考虑 dp
设置 End[i][j] 表示以a[i]、b[j]结尾的串的最大连续段长度。
设置 dp[i][j] 表示a[1] - a[i]串 和 b[1] - b[j]串的 最优特殊LCS。
那么转移
if(End[i][j]>=k)dp[i][j]=max(dp[ip][jp]+p);(k<=p<=End[i][j])
elsedp[i][j]=max(dp[i1][j],dp[i][j1]);
但是这样转移是O(n^3)会T。
发现对于第一个转移来讲,只有两种情况(1) 不拆开以a[i]、b[j]结尾的最大连续子串;(2) 拆开,肯定拆到a[i-k]、b[j-k]是最优的。
那么转移就可以变到O(1)了。这样时间复杂度O(n^2)。
dp[i][j]=max(dp[ik][jk]+k,dp[iEnd[i][j]][jEnd[i][j]]+End[i][j]);
AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 3 * 1e6 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
int End[2200][2200], start[2200][2200];
int dp[2200][2200];
char a[2200], b[2200];
int main()
{
    int k;
    while(scanf("%s%s", a+1, b+1) != EOF) {
        scanf("%d", &k);
        int la = strlen(a+1), lb = strlen(b+1);
        End[0][0] = 0;
        for(int i = 1; i <= la; i++) {
            for(int j = 1; j <= lb; j++) {
                if(a[i] == b[j]) {
                    End[i][j] = End[i-1][j-1] + 1;
                }
                else {
                    End[i][j] = 0;
                }
                dp[i][j] = 0;
            }
        }
        for(int i = 1; i <= la; i++) {
            for(int j = 1; j <= lb; j++) {
                if(End[i][j] >= k) {
                    dp[i][j] = max(dp[i - k][j - k] + k, dp[i - End[i][j]][j - End[i][j]] + End[i][j]);
                }
                else {
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
                }
            }
        }
        printf("%d\n", dp[la][lb]);
    }
    return 0;
}

题目链接:HZAUoj 1016: Array C 【贪心】

题意:分别给定n个数a[]和b[]。现在可以选择改变a[](只能减小,最小为0),且要保证 ni=1a[i]>=m 。问你最小的 ni=1a[i]a[i]b[i]

思路:显然,最后的 ni=1a[i]==m 才是最优的。那么只要考虑将a[]的和减少到m就可以了,怎么减少呢?肯定先选择对整体贡献最大的减小。考虑第i个数对整体的贡献为 a[i]a[i]b[i] ,当 a[i] 减一时有 (a[i]1)(a[i]1)b[i] ,第一个减第二个就是减少 a[i] 的代价,我们肯定选择代价最大的先减。那么用个优先队列维护就好了。

AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 3 * 1e6 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
struct Node {
    int id, cost;
    friend bool operator < (Node a, Node b) {
        return a.cost < b.cost;
    }
};
int a[1010], b[1010];
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF) {
        int sum = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum += a[i];
        }
        int sub = sum - m;
        priority_queue<Node> Q; Node now;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &b[i]);
            now.id = i; now.cost = (2 * a[i] - 1) * b[i];
            Q.push(now);
        }
        LL ans = 0;
        while(sub--) {
            now = Q.top(); Q.pop(); a[now.id]--;
            now.cost = (2 * a[now.id] - 1) * b[now.id];
            Q.push(now);
        }
        for(int i = 1; i <= n; i++) {
            ans += a[i] * a[i] * b[i];
        }
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值