洛谷P1415 拆分数列[序列DP 状态 打印]
题目背景
【为了响应党中央勤节俭、反铺张的精神,题目背景描述故事部分略去^-^】
题目描述
给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数。如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小;如果有多组解,则使得第一个数尽量大;如果仍有多组解,则使得第二个数尽量大,依次类推……)。
输入输出格式
输入格式:
共一行,为初始的数字。
输出格式:
共一行,为拆分之后的数列。每个数之间用逗号分隔。行尾无逗号。
输入输出样例
[1]
3456
[2]
3546
[3]
3526
[4]
0001
[5]
100000101
[1]
3,4,5,6
[2]
35,46
[3]
3,5,26
[4]
0001
[5]
100,000101
说明
【题目来源】
lzn改编
【数据范围】
对于10%的数据,输入长度<=5
对于30%的数据,输入长度<=15
对于50%的数据,输入长度<=50
对于100%的数据,输入长度<=500
看了题解
官方题解:
《拆分数列》解题报告
By lzn 动态规划常规题。
第一步先求出最后的那个数最小为多少。(为了叙述方便,记T(i,j)表示从原数列下标i取到j的数字组成的数。)只需正向dp一次,dp1[i]表示前i个数字分成任意多个递增数且最后的数最小时,最后的数为T(dp1[i],i)。则dp1[i]=max(j),(T(dp1[j-1],j-1)<T(j,i))。
第二步要求最后一个数确定的情况下,前面的数字按字典序尽量大的解。类似上面的方法反向动归一次即可。
算法复杂度o(l^3)。由于数据大部分为随机,实际运行效率接近l^2。
我的实现是:
第一步,d[i]表示以i结尾的序列最后一个数最小的起始下标d[i],转移同上
第二步,f[i]表示从i开始的序列第一个数最大的终止下标f[i],转移f[i]=max{j|T(i,j)<T(j+1,f[j+1])}
打印时从1开始沿f走就行了
注意:
1.字符串比较处理前导0,并且我在遇到全0串时返回了false,因为这样的划分不合法
2.初始化d[i]=1
3.第一次95分,有一个数据1234050,我的程序无法把050划分成一个
解决措施是把最后一个数前面的前导0的f值都指向n
经验:
1.分两步求解
2.非常特别的状态表示,无法直接保存数的大小,所以保存序列中下标
3.字符处理成数字注意前导0
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=,INF=2e9+;
char s[N];
int n,a[N];
bool small(int l1,int r1,int l2,int r2){
while(l1<=r1&&a[l1]==) l1++;
while(l2<=r2&&a[l2]==) l2++; if(r1-l1+==||r2-l2+==) return false;//hello
if(r1-l1+<r2-l2+) return true;
if(r1-l1+>r2-l2+) return false; int len=r1-l1+;
for(int i=;i<len;i++){
if(a[l1+i]<a[l2+i]) return true;
if(a[l1+i]>a[l2+i]) return false;
}
return false;
}
int d[N];
void dp1(){
for(int i=;i<=n;i++){
d[i]=;
for(int j=i;j>=;j--)
if(small(d[j-],j-,j,i)) {d[i]=j;break;}
}
//for(int i=1;i<=n;i++) printf("d %d %d\n",i,d[i]);
}
int f[N];
void dp2(){
f[d[n]]=n;int zero=d[n];
while(a[zero-]==) f[zero-]=n,zero--; for(int i=d[n]-;i>=;i--){
for(int j=d[n]-;j>=i;j--)
if(small(i,j,j+,f[j+])) {f[i]=j;break;}
} //for(int i=1;i<=n;i++) printf("f %d %d\n",i,f[i]);
//system("pause");
}
int main(){
scanf("%s",s+);
n=strlen(s+);
for(int i=;i<=n;i++) a[i]=s[i]-'';
dp1();
dp2();
int pos=,flag=;
while(pos<=n){//printf("pos %d %d\n",pos,f[pos]);
if(flag) putchar(',');
flag=;
for(int i=pos;i<=f[pos];i++) printf("%d",a[i]);
pos=f[pos]+;
}
}
洛谷P1415 拆分数列[序列DP 状态 打印]的更多相关文章
- 洛谷P1415 拆分数列(dp)
题目链接:传送门 题目: 题目背景 [为了响应党中央勤节俭.反铺张的精神,题目背景描述故事部分略去^-^] 题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输 ...
- 洛谷 P1415 拆分数列 解题报告
拆分数列 题目背景 [为了响应党中央勤节俭.反铺张的精神,题目背景描述故事部分略去^-^] 题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数. 如果有多组解,则输出使得最后一个 ...
- 洛谷P1415 拆分数列
题目背景 [为了响应党中央勤节俭.反铺张的精神,题目背景描述故事部分略去^-^] 题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输出使得最后一个数最小的同时 ...
- 洛谷 2577 [ZJOI2005]午餐——序列dp
题目:https://www.luogu.org/problemnew/show/P2577 可以从只有一个窗口的角度思考出一个贪心结论.就是应当按吃饭时间(不算打饭时间)从大到小排序.这样交换相邻两 ...
- 洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP
洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他. 玩具上有一个数列,数列中某些项的值可能会 ...
- 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)
洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\).我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...
- 洛谷 2023 [AHOI2009]维护序列
洛谷 2023 [AHOI2009]维护序列 洛谷原题传送门 这个题也是一道经典的线段树模版(其实洛谷的模版二改一下输入顺序就能AC),其中包括区间乘法修改.区间加法修改.区间查询三个操作. 线段树的 ...
- 洛谷P2023 [AHOI2009]维护序列(线段树区间更新,区间查询)
洛谷P2023 [AHOI2009]维护序列 区间修改 当我们要修改一个区间时,要保证 \(ax+b\) 的形式,即先乘后加的形式.当将区间乘以一个数 \(k\) 时,原来的区间和为 \(ax+b\) ...
- 洛谷 P2704 [NOI2001]炮兵阵地 (状态压缩DP+优化)
题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...
随机推荐
- Xamarin 免费了,你能做什么?
3月底,微软正式宣布:Xamarin免费了!那么,你能做什么? 抢先一步,用Xuni助力你的Xamarin开发! Xamarin是什么 Xamarin含Xamarin.Andoid,Xamarin.i ...
- 增加线程异步发送消息的方法二(Runnable)
//获取当前时间:毫秒 long a = System.currentTimeMillis(); System.out.println("a :" + a); try { //更改 ...
- 增加线程异步发送消息的方法一(Thread)
@RequestMapping(value="order/updateOrder.do") public String updateOrder(HttpServletRequest ...
- js设置、获取单值cookie和多值cookie
js设置.获取单值cookie和多值cookie,代码如下: var CookieUtil = (function () { var Cookie = function () { // 获取单值coo ...
- 在Python应用中使用MongoDB
Python是开发社区中用于许多不同类型应用的强大编程语言.很多人都知道它是可以处理几乎任何任务的灵活语言.因此,在Python应用中需要一个什么样的与语言本身一样灵活的数据库呢?那就是NoSQL,比 ...
- 【算法】PHP实现冒泡排序和快速排序--防遗忘
有没有这样的感觉,排序算法虽然简单,但是没看过一次,一会就又忘了,所以有必要 自己使用实际的代码运行实现,才记忆牢固,为此Mark //需求:将数组中元素,从大到小排列$a = array(11, 2 ...
- 谷歌浏览器下载地址 chrome最新版本 百度云地址
每次下载更新谷歌浏览器是一件很蛋疼的事情.百度搜索"谷歌浏览器下载地址",居然有很多骗子网站,相信有很多不知所以的人中招了.收集了一些chrome的安装包,放在了百度云里面(打不开 ...
- 关于float和margin
1.同级存在浮动,如mid的前面left浮动(mid不浮动),margin则相对于父元素,mid的margin-left不是相对于left,而是相对于con(可以想象,如果left不浮动,则mid和l ...
- hibernate(2) —— 主键策略
框架提供了三种主键生成方式,一种是由用户自己维护,一种是由hibernate框架维护,另一种是由数据库维护. 自己维护就是在插入数据的时候,一定要指定主键的值,否则会出错,如果由框架维护和由数据库维护 ...
- JavaScript 变量
一,JavaScript 变量(存储信息的容器) 与代数一样,JavaScript 变量可用于存放值(比如 x=2)和表达式(比如 z=x+y). 变量可以使用短名称(比如 x 和 y),也可以使用描 ...