题目链接:点击查看

题目大意:给出一个长度为 nnn 的数列,现在需要将其划分成 kkk 段,使得贡献和最小

对于每段区间 [l,r][l,r][l,r] 的贡献为,其中每个数字,其最后一次出现的位置减去其首次出现的位置

输出最小贡献

题目分析:区间划分,经典的 dpdpdp 问题,dpi,jdp_{i,j}dpi,j​ 代表前 iii 个数划分为 jjj 个区间的最优解,两种转移方程:

  1. dpi,j=min(dpi−1,j+(ai属于上一段的贡献),dpi−1,j−1+(ai独成一段的贡献))dp_{i,j}=min(dp_{i-1,j}+(a_i属于上一段的贡献),dp_{i-1,j-1}+(a_i独成一段的贡献))dpi,j​=min(dpi−1,j​+(ai​属于上一段的贡献),dpi−1,j−1​+(ai​独成一段的贡献))
  2. dpi,j=min(dpk,j−1+val(k+1,i))dp_{i,j}=min(dp_{k,j-1}+val(k+1,i))dpi,j​=min(dpk,j−1​+val(k+1,i))

以上,第一种转移方程的时间复杂度是 O(n∗m)O(n*m)O(n∗m) 的,缺点是无法知晓最后一段区间的起点

第二种转移方程的时间复杂度是 O(n∗n∗m)O(n*n*m)O(n∗n∗m) 的,可以知晓最后一段区间的起点

就本题而言,我们只能选择第二种转移方程,所以考虑利用数据结构优化掉一维 nnn

不难发现对于动态规划的第二维是可以滚动的,所以不妨在固定第二维后,将第一维的信息扔进线段树里,这样就可以 O(logn)O(logn)O(logn) 去维护区间最小值了,此时线段树中的每个节点实质上维护的是 dpi+val(i+1,cur)dp_i+val(i+1,cur)dpi​+val(i+1,cur),其中 curcurcur 就是第一维更新到的位置,val(l,r)val(l,r)val(l,r) 就是区间 [l,r][l,r][l,r] 中的贡献,也就是题目所述

查询的话直接查询区间最小值即可,现在问题转换为了,在加入 aia_iai​ 后,如何更新线段树中的信息呢?

感觉本题的难点就是这里了,我思考到这里卡住了,去请教的冰哥,明白了之后就豁然开朗了

因为从前往后加入 aia_iai​ 之后,并不会影响 aia_iai​ 首次出现的位置,只会影响 aia_iai​ 最后一次出现的位置,所以我们记 last[ai]last[a_i]last[ai​] 为 aia_iai​ 最后一次出现的位置,此时就将 [0,cur][0,cur][0,cur] 的区间划分为了两段:[0,last[ai]−1],[last[ai],cur][0,last[a_i]-1],[last[a_i],cur][0,last[ai​]−1],[last[ai​],cur],为什么这样划分呢,注意到上面提到的,线段树中节点维护的信息是:dpi+val(i+1,cur)dp_i+val(i+1,cur)dpi​+val(i+1,cur),当此处的 iii 取到 [last[ai],cur][last[a_i],cur][last[ai​],cur] 时,val(i+1,cur)=0val(i+1,cur)=0val(i+1,cur)=0,即不做贡献,而取到 [0,last[ai]−1][0,last[a_i]-1][0,last[ai​]−1] 时,val(i+1,cur)val(i+1,cur)val(i+1,cur) 统一增大了 i−last[ai]i-last[a_i]i−last[ai​],所以只需要用线段树区间更新即可

代码:

// Problem: E. Partition Game
// Contest: Codeforces - Codeforces Round #721 (Div. 2)
// URL: https://codeforces.com/contest/1527/problem/E
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f;
}
template<typename T>
inline void write(T x)
{if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=4e4+100;
struct Node {int l,r,mmin,lazy;
}tree[N<<2];
int dp[N],a[N],last[N];;
void pushup(int k) {tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);
}
void pushdown(int k) {if(tree[k].lazy) {int lz=tree[k].lazy;tree[k].lazy=0;tree[k<<1].mmin+=lz;tree[k<<1|1].mmin+=lz;tree[k<<1].lazy+=lz;tree[k<<1|1].lazy+=lz;}
}
void build(int k,int l,int r) {tree[k]={l,r,inf,0};if(l==r) {tree[k].mmin=dp[l];return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
void update(int k,int l,int r,int val) {if(tree[k].l>r||tree[k].r<l) {return;}if(tree[k].l>=l&&tree[k].r<=r) {tree[k].mmin+=val;tree[k].lazy+=val;return;}pushdown(k);update(k<<1,l,r,val);update(k<<1|1,l,r,val);pushup(k);
}
int query(int k,int l,int r) {if(tree[k].l>r||tree[k].r<l) {return inf;}if(tree[k].l>=l&&tree[k].r<=r) {return tree[k].mmin;}pushdown(k);return min(query(k<<1,l,r),query(k<<1|1,l,r));
}
int main()
{#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int n,k;read(n),read(k);for(int i=1;i<=n;i++) {read(a[i]);}memset(dp,inf,sizeof(dp));dp[0]=0;for(int j=1;j<=k;j++) {build(1,0,n);memset(last,0,sizeof(last));for(int i=1;i<=n;i++) {if(last[a[i]]) {update(1,0,last[a[i]]-1,i-last[a[i]]);}last[a[i]]=i;dp[i]=query(1,0,i-1);}}printf("%d\n",dp[n]);return 0;
}

CodeForces - 1527E Partition Game(dp+线段树)相关推荐

  1. hdu5489 Removed Interval dp+线段树优化

    现在看这题居然直接秒了...去年看的时候还以为神题.. 设以第i项为结尾的lis前缀为f[i],以第j项为结尾的lis后缀为g[i],如果求出f[i]和g[j],然后枚举i,快速找到最大的满足a[j] ...

  2. Codeforces 444C DZY Loves Colors 线段树区间更新

    // Codeforces 444C DZY Loves Colors 线段树区间更新// 题目链接:// http://codeforces.com/problemset/problem/444/C ...

  3. Codeforces 833B 题解(DP+线段树)

    题面 传送门:http://codeforces.com/problemset/problem/833/B B. The Bakery time limit per test2.5 seconds m ...

  4. CodeForces - 1557D Ezzat and Grid(线段树+dp)

    题目链接:点击查看 题目大意:给出 nnn 个 010101 串,现在问最少需要删掉多少个串,才能使得剩下的串拼起来是连通的 规定两个 010101 串是连通的,当且仅当存在至少一列,在两个串中都为 ...

  5. Codeforces Round #620 (Div. 2) F2. Animal Observation (hard version) dp + 线段树

    传送门 文章目录 题意: 思路: 题意: 比如下面这个图: 思路: 对于这个题,比较容易就能考虑到dpdpdp,设f[i][j]f[i][j]f[i][j]为到了第iii行,覆盖了[j,j+k−1][ ...

  6. CodeForces - 960F[动态开点线段树优化dp]详解

    题意:给一张有向图,每条边有边权与编号,求一条最长的路径,这条路径的边权与编号都是递增的.(编号指输入顺序) 首先我们回忆一下普通得LIS得做法:就是dp[i]以第i个结尾得最长上升子序列的长度,那么 ...

  7. Codeforces Round #699 (Div. 2) E.Sorting Books(贪心+DP / 线段树)超高质量题解,看不懂来打我 ~

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 E - Sorting Books 一排书架上有 nnn 本书排成一排,每本书上有一个颜色 aia_i ...

  8. Codeforces 671D. Roads in Yusland(树形DP+线段树)

    调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...

  9. Codeforces 1398 F. Controversial Rounds —— 线段树+dp

    This way 题意: 给你一个字符串,有些位置是已知的,有些是未知的,从位置1开始,如果有连续的0或者1大于等于k个,那么就算一轮游戏,然后0,1重新计数.问你当k=1~n的时候,游戏轮数最多是多 ...

最新文章

  1. leetcode[161] One Edit Distance
  2. spring-boot+swagger实现WebApi文档
  3. ethercat 网卡不兼容_曾经的洋垃圾万兆网卡无人问津因为一张转接卡如今身价暴涨数十倍...
  4. javascript笔记整理(数据类型强制/隐式转换 )
  5. Java项目课程05:系统设计
  6. cpu使用率_单片机里面的CPU使用率是什么鬼?
  7. 随想录(skyeye中的soc仿真)
  8. c#如何实现IComparable接口
  9. MFC界面设计入门篇
  10. 你应该知道的十大常见黑客技术
  11. (SQL)使用Excel连接数据库
  12. 获取网站图标icon
  13. 什么是360度绩效评估反馈?
  14. Byte历险记(tomcat+web游历)
  15. 探花交友10-数据统计与内容审核
  16. 无需公网IP,在外远程访问NAS威联通QNAP【内网穿透】
  17. opencv直线拟合cv::fitLine()
  18. PC微信界面透明度修改美化自制小工具+壁纸1.1
  19. 电磁场与仿真软件(35)
  20. Frame skipped from debugging during step-in. VSCode调试无法定位其它库中代码的解决办法

热门文章

  1. 同样的sql在两个oracle,sql – 从两个会话INSERT到唯一列相同的值(Oracle)
  2. 核心组件:IRule
  3. ZkServer服务启动的逻辑-NIOServerCnxnFactory.start
  4. 数据库事务原理详解-数据库隔离级别
  5. 常用函数式接口之Supplier
  6. xml方式实现aop-切点表达式的写法
  7. 反射_Class对象功能_获取Field
  8. HDFS的API操作-小文件的合并
  9. 产品操作-查询全部产品
  10. 请使用日期时间相关的API,计算出一个人已经出生了多少天