HDU 4521 LIS变形 简单dp 线段树 单点更新 区间最值

博客围绕一个由n个数组成的序列展开,要从左到右取数组成新的递增序列,相邻元素位置间隔至少为d且原序列个数尽可能多。题解指出这是LIS的变形,需把满足条件的LIS都求出取最大值,因数据范围,求dp时要加线段树进行单点更新和区间最值操作,还给出了AC代码。

传送门:题目

题意:

给一个由n个数组成的序列,然后从左到右取一些数组成一个新序列,这个新序列满足一些条件:

  • 新序列是递增的
  • 原序列取得过程中,相邻两个元素的位置间隔至少为d
  • 原序列的个数尽可能多

题解:

第一个条件明显是LIS,第二个题目告诉我们这道题是LIS的变形,说是变形,其实就改了一点,我们在求普通LIS的时候,dp[i]=dp[i-1]+1,这道题:dp[i]=dp[i-d-1]+1就好了。然后第三个条件,就是把所有满足条件的LIS都求出来,然后取个最大值就好了。
数据范围 105 10 5 ,我们在求dp的时候不能 n2 n 2 搜索了,要加个线段树,单点更新,区间最值 。

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;

const int maxn = 110000;
int dp[maxn], a[maxn];
/******************线段树模板**********************/
int SegTree[maxn * 4];
void BuildTree(int l, int r, int rt) {//建树,lr是总区间,rt是根结点一般为1
    if (l == r) {
        SegTree[rt] = 0; //初始化叶节点
        return ;
    }
    int m = (l + r) >> 1;
    BuildTree(l, m, rt << 1);
    BuildTree(m + 1, r, rt << 1 | 1);
    SegTree[rt] = SegTree[rt << 1] + SegTree[rt << 1 | 1];
}
int Query(int L, int R, int l, int r, int rt) {//区间查询,LR是查询区间,lr是总区间,rt是根结点一般为1
    if (L > R)//注意这里,我第一开始没加,一直MLE
        return 0;
    if (l >= L && r <= R)
        return SegTree[rt];
    int m = (l + r) >> 1;
    int ans1 = 0, ans2 = 0;
    if (L <= m)
        ans1 = Query(L, R, l, m, rt << 1);
    if (R > m)
        ans2 = Query(L, R, m + 1, r, rt << 1 | 1);
    return max(ans1, ans2);
}
void Update(int point, int value, int l, int r, int rt) {//单点更新,把point点的值改为value,lr是总区间,rt是根结点一般为1
    if (l == r) {
        SegTree[rt] = max(value, SegTree[rt]);
        return;
    }
    int m = (l + r) >> 1;
    if (point <= m)
        Update(point, value, l, m, rt << 1);
    else
        Update(point, value, m + 1, r, rt << 1 | 1);
    SegTree[rt] = max(SegTree[rt << 1] , SegTree[rt << 1 | 1]);
}
/******************线段树模板**********************/
int main(void) {
    int n, d;
    while (cin >> n >> d) {
        memset(dp, 0, sizeof dp);
        int mmax = 0, ans = 0;
        for (int i = 1; i <= n; i++)
            cin >> a[i], ++a[i], mmax = max(mmax, a[i]);
        BuildTree(1, mmax, 1);
        for (int i = 1; i <= n; i++) {
            if (i - d - 1 >= 1)
                Update(a[i - d - 1], dp[i - d - 1], 1, mmax, 1);
            dp[i] =  Query(1, a[i] - 1, 1, mmax, 1) + 1;
            ans = max(dp[i], ans);
        }
        cout << ans << endl;
    }
    return 0;
}
基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现和扩展应用。; 适合人群:具备电力系统基础知识和Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值