首页 > 其他分享 >用分治处理决策单调性问题

用分治处理决策单调性问题

时间:2023-06-05 19:55:48浏览次数:58  
标签:int 分治 决策 long mid 单调 转移 dp

决策单调性是 dp 转移方程的一种性质。一般而言,我们有许多方法优化一个具有决策单调性的转移方程。

这里主要讲解一种用分治解决决策单调性问题的方法。

引入

先看一道题:CF868F

我们可以想到一个 \(O(n^2k)\) 暴力。定义 \(dp_{i, j}\) 为令点 \(i\) 为第 \(j\) 段的最后一个点产生的最小代价。则可以得出:

\[dp_{i, j} = min(dp_{k, j - 1}+f(k + 1, i))(k<i) \]

其中 \(f(k+1,i)\) 即为这一段的代价。答案即为 \(dp_{n, k}\)。这是好求的。

显然,我们需要砍掉一个 \(n\) 才能通过此题。然后我们通过打表得到了一个性质:对于 \(dp_{i, j}\) 与 \(dp{k,j}\) 的转移点(这两个状态由它们的转移点转移而来)\(I,K\),如果 \(i>k\),则 \(I \ge K\)。也就是说,这个转移具有决策单调性!

发现

也许已经有人想要大显身手了,但是我们先来关注一下我们是如何得出决策单调性的。

让我们了解一下四边形不等式。对于 \(dp_i = min(g_j+f(j, i))\),如果有四个点 \(a<b<c<d\) 且 \(f(a,d) + f(b,c) \ge f(a, c) + f(b,d)\),那么我们就说这个转移方程满足四边形不等式(最大也是可以的,反过来就行了)。这一性质也被称作“包含劣于相交”。

那么我们发现,如果一个形如 \(dp_i = min(g_j+f(j, i))\) 的转移方程满足四边形不等式,那么这个方程具有决策单调性

考虑证明:考虑反证法,然后读者自证。

在实际做题中,我们通过感觉感应到四边形不等式的存在(有时也会直接感应到决策单调性),然后打表加以证明。

分治

我们并不知道这个代价函数除了决策单调性以外的性质,也就是说,尽管我们知道了点 \(i\) 的决策点 \(d_i\),对于大于点 \(i\) 的点 \(j\),我们仍然要暴力枚举转移点 \([a_i, j]\)。这很容易被卡掉。

考虑更好地排除转移点,对于需要求解的区间 \([l, r]\),我们取区间中点 \(mid\),并暴力计算出 \(mid\) 的转移点 \(d_mid\)。如果原区间转移范围在 \([L,R]\) 之间,那么我们可以分两半。\([l,mid]\) 转移范围在 \([L,d_mid]\),\([mid+1,r]\) 转移范围在 \([d_mid, R]\)。

考虑证明时间复杂度。对于分治的每一层,我们暴力计算的时间复杂度总和都是 \(O(n)\)。但由于分治树只有 \(\log n\) 层,所以总复杂度变为 \(n \log n\)。

修改

现在我们需要解决的问题,是我们无法快速求出 \(f(l, r)\)。

我们发现虽然我们无法快速求出 \(f(l, r)\),但我们可以快速地由 \(f(l+1,r)\) 转移到 \(f(l,r)\)。

这时我们就有一个很憨的想法:类似莫队,我们直接在上一次查询的基础上一个一个暴力转移。

很神奇的是,这个方法复杂度还是 \(O(n \log n)\) 的!考虑两个指针进行跳跃。对于从 \([l,d_mid]\) 到 \([d_mid, r]\) 的跳跃,时间复杂度不会超过区间长度。那么这一层的时间复杂度总和还是 \(O(n)\) 的。然后分治树只有 \(\log n\) 层,于是总时间复杂度还是 \(O(n \log n)\)。

实现

注意由于这里也是一个一个的跳跃,所以跳跃顺序和莫队一样有讲究。具体可以看代码。

#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;

const int N = 1e5 + 5, K = 21;

int n, k;
int a[N];

long long dp[N], g[N];

long long ton[N];

long long f(int L, int R) {
  static long long l = 1, r = 0, ans = 0;
  
  auto del = [&](int i) {
    ton[a[i]]--;
    ans -= ton[a[i]];
  };
  auto add = [&](int i) {
    ans += ton[a[i]];
    ton[a[i]]++;
  };
  
  while (l > L) add(--l);
  while (r < R) add(++r);
  while (l < L) del(l++);
  while (r > R) del(r--);//important

  return ans;
}

void solve(int l, int r, int dl, int dr) {
  int mid = (l + r) >> 1, dec = 0;
  for (int i = dl; i <= min(dr, mid - 1); ++i) {
    if (dp[mid] > g[i] + f(i + 1, mid)) {
      dp[mid] = g[i] + f(i + 1, mid);
      dec = i;
    }
  }

  if (l == r) return ;
  solve(l, mid, dl, dec);
  solve(mid + 1, r, dec, dr);
}

signed main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  cin >> n >> k;
  for (int i = 1; i <= n; ++i) cin >> a[i];

  long long tmp = 0;
  for (int i = 0; i <= n; ++i) {
    tmp += ton[a[i]];
    dp[i] = tmp;
    ton[a[i]]++;
  }
  for (int i = 1; i <= n; ++i) ton[i] = 0;

  for (int lask = 1; lask <= k - 1; ++lask) {
    for (int i = 1; i <= n; ++i) g[i] = dp[i], dp[i] = 2e13;
    solve(lask + 1, n, lask, n - 1);
  }

  cout << dp[n] << endl;

  return 0;
}

练习

P4360 锯木厂选址

P5774 任务分配问题

标签:int,分治,决策,long,mid,单调,转移,dp
From: https://www.cnblogs.com/closureshop/p/17458794.html

相关文章

  • 单调队列
    写法首先要有一个双端队列:structMy_dequeue{inthh=1,tt=0,q[N];voidclear(){hh=1;tt=0;}voidpush_front(intk){q[--hh]=k;}voidpush_back(intk){q[++tt]=k;}voidpop_front(){hh++;}voidpop_back(){tt--;}intfront(){returnq[hh];......
  • 0003.有监督学习之决策树
    一、什么是决策树决策树(DecisionTree)是有监督学习中的一种算法,并且是一种节本的分类与回归的方法。即决策树有两种:分类树和回归树。那什么事决策树了?简单点说就是二元判定,从头到尾逐次判定其归属类型。从上述案例,我们很容易理解:决策树算法的本质就是二元判定的属性结构,我们......
  • 强化学习基础篇【1】:基础知识点、马尔科夫决策过程、蒙特卡洛策略梯度定理、REINFORCE
    强化学习基础篇【1】:基础知识点、马尔科夫决策过程、蒙特卡洛策略梯度定理、REINFORCE算法1.强化学习基础知识点智能体(agent):智能体是强化学习算法的主体,它能够根据经验做出主观判断并执行动作,是整个智能系统的核心。环境(environment):智能体以外的一切统称为环境,环境在与智能体......
  • python spark 决策树 入门demo
    Refertothe DecisionTree and DecisionTreeModel formoredetailsontheAPI.frompyspark.mllib.treeimportDecisionTree,DecisionTreeModelfrompyspark.mllib.utilimportMLUtils#LoadandparsethedatafileintoanRDDofLabeledPoint.data=MLUtils.l......
  • GBDT(MART) 迭代决策树入门教程 | 简介
    GBDT(MART)迭代决策树入门教程|简介 在网上看到一篇对从代码层面理解gbdt比较好的文章,转载记录一下:        GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结......
  • Python进行多输出(多因变量)回归:集成学习梯度提升决策树GRADIENT BOOSTING,GBR回归训练
    原文链接: http://tecdat.cn/?p=25939最近我们被客户要求撰写关于多输出(多因变量)回归的研究报告,包括一些图形和统计输出。在之前的文章中,我们研究了许多使用多输出回归分析的方法。在本教程中,我们将学习如何使用梯度提升决策树GRADIENTBOOSTINGREGRESSOR拟合和预测多输出回归......
  • 决策树
    决策树​ 决策树是一种机器学习的方法。决策树的生成算法有ID3(信息增益),C4.5(信息增益率)和CART(Gini系数)等。决策树是一种树形结构,其中每个内部节点表示一个属性上的判断,每个分支代表一个判断结果的输出,最后每个叶节点代表一种分类结果。​ 构造树的基本想法是随着树深度的增加,节......
  • adr 方便的架构决策记录方法
    adr是编译中方便的架构决策记录方法,同时也纳入了技术雷达中,是一个很值得使用的模式包含的内容一般会包含标题,状态,上下文,决策,以及影响,aws官方包含了很不错的例子,值得学习下格式对于存储格式没明确要求,实际上github有一个adr的组织,包含了不少实现工具,很值得参考学习对于开发......
  • 第六课 决策树
          决策树(DecisionTree)是为数不多存活下来的机器学习算法之一,因其良好的性能和可解释性,被广泛应用于生产和生活当中。1、决策树初体验      图1是一个女方是否决定相亲的决策树示例,通过年龄、长相、收入、职业四个维度进行决策判断,媒人同时介绍了两个男方,男......
  • 帆软决策报表tab 多sheet导出
    新建cpt普通报表,将多tab语句放入在决策报表自定义导出按钮,定义导出事件`varurl="${servletURL}?viewlet=xx/进销存日报导出.cpt"varregion=this.options.form.getWidgetByName("regioncode").getValue();varcity=this.options.form.getWidgetByName("citycode").get......