应要求写一下这个题的题解。

我的DP很奥(奇)妙(怪),不过跟标算还是殊途同归的(反正怎么做都行……)

先讲一下奥妙的性质吧。

首先,在最终序列中,每个数最多出现一段,并且,对于出现的数,每段数两两之间的相对位置相较原序列保持不变。

然后,你还可以发现,一个数可以延伸到最左的左端点、和最右的右端点,这些都是可以算出来的。

如果我们不考虑操作次数的限制,这个问题就变成了,按顺序给你一堆区间,让你在每个区间里选一小段,使选出来的区间不重叠地覆盖整个序列,并且区间之间的相对位置要按照给定的顺序。

下面考虑次数限制,可以发现,对于一个合法的目标序列(合法的意思就是符合前面的要求,对应到题目就是能够通过操作得到),最优的操作方案显然是按由小到大的顺序对每个数进行操作,并且对每个数之多操作1次。

进一步考虑,发现,对于一个数,我们不需要对它进行操作,当且仅当该数不在最终序列中出现,或者该数在最终序列中出现的位置恰好仅为该数在原序列中的位置。

换句话说,操作k次就是限制了,你的最终序列只能有k段数(如果一个数只在原序列出现的位置出现,那么就不算一段数,需要特判)

之后就是dp,令dp[k][i]表示现在已经有k段数,并且当前计算到原序列左起第i个数的段。

作者太懒了,反正是普及组DP,你们自己脑补好了,那个特判还是要想一想的(对于我这种老年选手)。

(我觉得我已经说得很详细了啊TaT)

(嘛...主要是好困想碎叫QuQ)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define N 505
#define P 1000000007 using namespace std;
inline int read(){
int ret=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9'){
ret=ret*10-48+ch;
ch=getchar();
}
return ret;
} int kk;
int n,a[N];
int l[N],r[N];
int dp[N][N],dlt[N]; int main(){
n=read();kk=read();
for (int i=1;i<=n;++i) a[i]=read();
memset(dp,0,sizeof(dp));dp[0][0]=1;
for (int i=1;i<=n;++i){
int l,r;
for (l=i;l>1&&a[l-1]<a[i];--l);
for (r=i;r<n&&a[r+1]<a[i];++r);
(dp[kk][i]+=dp[kk][i-1])%=P;
for (int k=kk-1;k>=0;--k){
dlt[l-1]=0;
for (int j=l;j<=r;++j) dlt[j]=(dlt[j-1]+dp[k][j-1])%P;
for (int j=l;j<=r;++j) (dp[k+1][j]+=dlt[j])%=P;
(dp[k][i]+=dp[k][i-1])%=P;
(dp[k+1][i]+=P-dp[k][i-1])%=P;
}
}
int ans=0;
for (int i=0;i<=kk;++i) (ans+=dp[i][n])%=P;
printf("%d\n",ans);
return 0;
}

  

bzoj4621: Tc605的更多相关文章

  1. BZOJ4621 Tc605(动态规划)

    容易发现最终序列所有数字的相对顺序不变,一个数字可能的覆盖范围由两边第一个比它大的数决定,且若不考虑次数限制所有这样的序列都可以变换得到.对于一个序列,其需要的最少变换次数显然就是覆盖了别的位置的数的 ...

  2. 【BZOJ4621】Tc605 DP

    [BZOJ4621]Tc605 Description 最初你有一个长度为 N 的数字序列 A.为了方便起见,序列 A 是一个排列. 你可以操作最多 K 次.每一次操作你可以先选定一个 A 的一个子串 ...

  3. bzoj 4621 Tc605 思想+dp

    4621: Tc605 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 328  Solved: 183[Submit][Status][Discuss ...

  4. bzoj 4621: Tc605 动态规划

    题解: 一道比较简单的题目 想着想着就把题目记错了..想成了可以把某段区间覆盖为其中一个数 其实是比较简单的 每个点的贡献一定是一个区间(就跟zjoi2018那题一样) 然后问题就变成了给你n个区间让 ...

  5. BZOJ 4621: Tc605

    Description 最初你有一个长度为 N 的数字序列 A.为了方便起见,序列 A 是一个排列. 你可以操作最多 K 次.每一次操作你可以先选定一个 A 的一个子串,然后将这个子串的数字全部变成原 ...

  6. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

随机推荐

  1. JVM之内存结构

    JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...

  2. python之最强王者(7)——元组(tuple)

    1.序列(sequence): 说明:在前面的字符串列表中其实我们已经用到了序列,之所以放到这篇来讲主要是为了承上启下,方便理解和记忆. python的数据访问模型:直接存取 ,序列 ,映射 对非容器 ...

  3. Hibernate(二)__简单实例入门

    首先我们进一步理解什么是对象关系映射模型? 它将对数据库中数据的处理转化为对对象的处理.如下图所示: 入门简单实例: hiberante 可以用在 j2se 项目,也可以用在 j2ee (web项目中 ...

  4. Eclipse(一)

    Eclipse的初步学习

  5. LightGallery.js – 功能齐全的 Javascript Lightbox

    Lightgallery是一个轻量级的模块化.响应式的灯箱画廊,它允许您创建美丽的图像和视频画廊.借助缩略图插件的帮助,Lightgallery 允许您创建缩略图画廊.它支持触摸屏设备上滑动导航以及桌 ...

  6. JavaScript数组方法reduce解析

    Array.prototype.reduce() 概述 reduce()方法是数组的一个实例方法(共有方法),可以被数组的实例对象调用.reduce() 方法接收一个函数作为累加器(accumulat ...

  7. React Native学习笔记

    React 是使用ES6 ,支持JSX语法, 开发组件化web或native的工具. 现阶段使用Babel工具转换成ES5 代码. 组件通过props属性传递不变化的内容,UI通过state属性变动来 ...

  8. UI-切圆角、透明度、取消按钮点击高亮效果、按钮文字带下划线

    一.切UIView的某个角为圆角 如果需要将UIView的4个角全部都为圆角,做法相当简单,只需设置其Layer的cornerRadius属性即可(项目需要使用QuartzCore框架).而若要指定某 ...

  9. [Erlang 0119] Erlang OTP 源码阅读指引

      上周Erlang讨论群里面提到lists的++实现,争论大多基于猜测,其实打开代码看一下就都明了.贴出代码截图后有同学问这代码是哪里找的?   "代码去哪里找?",关于Erla ...

  10. Oracle XMLTable 使用教程与实例

    从Oracle 10g开始,甲骨文公司新增了XQuery和XMLTable两个功能作为处理XML的武器. XMLQuery一样,您可以使用XQuery语言构造XML数据和查询XML和关系数据.你可以使 ...