【Foreign】动态规划 [分治][DP]

动态规划  

Time Limit: 50 Sec  Memory Limit: 128 MB

Description

  一开始有n个数,一段区间的价值为这段区间相同的数的对数。
  我们想把这n个数切成恰好k段区间。之后这n个数的价值为这k段区间的价值和。
  我们想让最终这n个数的价值和尽可能少。
  例如6个数1,1,2,2,3,3要切成3段,一个好方法是切成[1],[1,2],[2,3,3],这样只有第三个区间有1的价值。因此这6个数的价值为1。

Input

  第一行两个数n,k。
  接下来一行n个数ai表示这n个数。

Output

  一个数表示答案。   

Sample Input

  10 2
  1 2 1 2 1 2 1 2 1 2

Sample Output

  8

HINT

  对于100%的数据1<=n<=100000,1<=k<=min(n,20),1<=ai<=n。

Solution

  首先,暴力DP非常显然,f[i][j] 表示分了 i 段,当前做到第 j 个元素的最小值。

  那么 f[i][j] = f[i - 1][k] + sum(k + 1, i)。我们打一个表,发现决策具有单调性

  但是显然,对于这道题,我们不能直接二分转移来的位置,由于sum并不好求。

  所以我们可以考虑运用分治。执行k次。Solve(l, r, L, R)表示 j∈[l, r],from∈[L, R]

  那么我们对于[l, r],考虑mid[L, R]中的哪一个转移过来,假设是MidFrom

  那么由于决策单调性,所以[l, mid - 1]决策点一定在[L, MidFrom][mid + 1, r]决策点一定在[MidFrom, R]

  移动两个指针now_l, now_r维护sum即可。(复杂度我也不会证明呀QWQ)

Code

 1 #include<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cmath>
 8 using namespace std;
 9 typedef long long s64;
10
11 const int ONE = 100005;
12 const int MOD = 1e9 + 7;
13 const s64 INF = 1e18;
14
15 int get()
16 {
17         int res = 1, Q = 1; char c;
18         while( (c = getchar()) < 48 || c > 57)
19             if(c == ‘-‘) Q = -1;
20         if(Q) res = c - 48;
21         while( (c = getchar()) >= 48 && c <= 57)
22             res = res * 10 + c - 48;
23         return res * Q;
24 }
25
26 int n, k;
27 int a[ONE], cnt[ONE];
28
29 s64 record[ONE], f[ONE], value;
30 int now_l, now_r;
31
32
33 void Move(int l, int r)
34 {
35         while(now_r < r) cnt[a[++now_r]]++, value += cnt[a[now_r]];
36         while(l < now_l) cnt[a[--now_l]]++, value += cnt[a[now_l]];
37         while(now_r > r) value -= cnt[a[now_r]], cnt[a[now_r--]]--;
38         while(l > now_l) value -= cnt[a[now_l]], cnt[a[now_l++]]--;
39 }
40
41 void Solve(int l, int r, int L, int R) //j=l~r, from = L~R
42 {
43         if(l > r) return;
44         int mid = l + r >> 1, MidFrom;
45         s64 Ans = INF;
46         for(int from = L; from <= R; from++)
47         {
48             if(from >= mid) break;
49             Move(from + 1, mid);
50             if(f[from] + value < Ans)
51                 Ans = f[from] + value, MidFrom = from;
52         }
53         record[mid] = Ans;
54         Solve(l, mid - 1, L, MidFrom);
55         Solve(mid + 1, r, MidFrom, R);
56 }
57
58 int main()
59 {
60         n = get();    k = get();
61         for(int i = 1; i <= n; i++)
62             a[i] = get();
63
64         for(int i = 0; i <= n; i++) f[i] = INF;
65         f[0] = 0;
66         for(int j = 1; j <= k; j++)
67         {
68             for(int i = 1; i <= n; i++) cnt[i] = -1;
69             now_l = now_r = 1; value = 0, cnt[a[1]] = 0;
70             Solve(1, n, 0, n - 1);
71             for(int i = 1; i <= n; i++)
72                 f[i] = record[i], record[i] = 0;
73         }
74         printf("%lld", f[n]);
75 }

时间: 2024-10-13 16:30:17

【Foreign】动态规划 [分治][DP]的相关文章

BZOJ 4518 [Sdoi2016]征途(分治DP)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4518 [题目大意] 给出一个数列,分成m段,求方差最小,答案乘上m的平方. [题解] 化简式子可以发现,就是求将数列分成m段,最小化和的平方和.设dp[i][j]表示处理到第i段,已经用了前j个数的最小代价,我们可以得到dp[i][j]=min(dp[i-1][k]+(s[j]-s[k])2),由于决策单调,可以分治DP. [代码] #include <cstdio> typede

POJ 3071 Football (动态规划-概率DP)

Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2768   Accepted: 1412 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all teams still in the

HDU 3507 Print Article(CDQ分治+分治DP)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3507 [题目大意] 将长度为n的数列分段,最小化每段和的平方和. [题解] 根据题目很容易得到dp[j]=min(dp[k]+(s[j]-s[k])2),因为是从前往后转移,且决策单调,因此在CDQ分治的同时进行分治DP即可. [代码] #include <cstdio> typedef long long LL; const int N=500005; int n,M,t; LL f[N],

POJ 2151 Check the difficulty of problems (动态规划-概率DP)

Check the difficulty of problems Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4522   Accepted: 1993 Description Organizing a programming contest is not an easy job. To avoid making the problems too difficult, the organizer usually exp

HDU 4336 Card Collector(动态规划-概率DP)

Card Collector Problem Description In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, for example, if you collect all the 108 people in the famous novel Water Margin, you will win an amazing award. As a

初探动态规划(DP)

学习qzz的命名,来写一篇关于动态规划(dp)的入门博客. 动态规划应该算是一个入门oier的坑,动态规划的抽象即神奇之处,让很多萌新 萌比. 写这篇博客的目标,就是想要用一些容易理解的方式,讲解入门动态规划的真正意义. 奶萌兔的温馨提示:建议先理解dfs哦~(本文以一种较为新奇的方式解释DP) 动态规划 那什么是动态规划? 来问问神奇的奶萌兔吧(强行盗梗)! (奶萌兔来给你讲解啦~虽然还在睡觉=w=) 动态规划(英语:Dynamic programming,简称DP)是一种在数学.管理科学.计

[hdu contest 2019-07-29] Azshara&#39;s deep sea 计算几何 动态规划 区间dp 凸包 graham扫描法

今天hdu的比赛的第一题,凸包+区间dp. 给出n个点m个圆,n<400,m<100,要求找出凸包然后给凸包上的点连线,连线的两个点不能(在凸包上)相邻,连线不能与圆相交或相切,连线不能相交但是可以有公共端点. 首先找出凸包,然后把n*n条边和m个圆算点到直线距离验证一下边是否与圆相交存到e[n][n]里. 然后显然是一个dp,但是我开始看错题目了以为不能有公共端点,能有公共端点的情况考虑一下像一个找三角形的过程,就是区间dp. 区间dp有一点妙的地方是最大区间范围是凸包点数而不用+1,因为连

Leetcode之动态规划(DP)专题-63. 不同路径 II(Unique Paths II)

初级题目:Leetcode之动态规划(DP)专题-62. 不同路径(Unique Paths) 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为“Finish”). 现在考虑网格中有障碍物.那么从左上角到右下角将会有多少条不同的路径? 网格中的障碍物和空位置分别用 1 和 0 来表示. 说明:m 和 n 的值均不超过 100. 示例 1: 输入: [   [0,0,0],  

codeforces 448C C. Painting Fence(分治+dp)

题目链接: codeforces 448C 题目大意: 给出n个杆子,每个杆子有一个长度,每次可以刷一行或一列,问最少刷多少次可以将整个墙刷成黄色. 题目分析: 首先我们能够想到,如果横着刷,为了得到最优解,当前刷的位置的下面也必须横着刷,然后对于每种情况都可以通过n次竖着刷得到整个黄色的墙. 所以我们采取分治的策略进行动态规划,也就是对于每个状态划分为两种情况讨论,如果要刷横向的话,最矮要刷到最矮的柱子的高度才可能得到比竖着刷优的解,然后就变成了多个具有相同性质的规模更小的墙,然后我们可以采取