洛谷P1415 拆分数列(dp)
题目链接:传送门
题目:
题目背景 【为了响应党中央勤节俭、反铺张的精神,题目背景描述故事部分略去^-^】
题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数。如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小;如果有多组解,则使得第一个数尽量大;如果仍有多组解,则使得第二个数尽量大,依次类推……)。
输入输出格式
输入格式: 共一行,为初始的数字。 输出格式: 共一行,为拆分之后的数列。每个数之间用逗号分隔。行尾无逗号。 输入输出样例
输入样例#: [] [] [] [] [] 输出样例#: []
,,,
[]
,
[]
,,
[] []
, 说明 【题目来源】 lzn改编 【数据范围】 对于10%的数据,输入长度<= 对于30%的数据,输入长度<= 对于50%的数据,输入长度<= 对于100%的数据,输入长度<=
dp练得还是太少了呀。其实复杂dp和大模拟很像,要从每个细节考虑,逐个击破,囫囵吞枣使不得。刚开始我乍一看贪心可用,强行贪心搜索,实际上时间复杂度没考虑,很多细节也没考虑到。。。而且搜索写得还很麻烦,写完了还很多bug,加了一通乱七八糟的特判,最后还是以WA告终。。。
思路:
·第一步:
根据题意,当然要先找最小的最后一个数。本来想贪心地从后开始搜索,第一个满足条件的就是最小,但是发现遇到0的时候状况千变万化,很难控制:比如:
100 000 104 123
搜索过程中会出现以下的情况:
① 100000 > 104,不满足
② 10000 > 0104,不满足
③ 1000 > 00104,不满足
像这样,连续出现的0会导致每次搜索失败都要回到之前的位置101,而不能直接回到最后一个数123,这就导致这样搜索的时间复杂度是指数级的,不可用。
但是从后往前找又想不到什么办法记录状态,不能用dp来做,僵硬。。。
于是想到考虑一个子问题:
子串被分割成若干个严格递增的数后,使得最后一个数最小时,找到最小的最后一个数。
然后可以惊奇地发现,如果之前的所有子串都计算完了,长度+1之后可以利用之前的结果:
假设当前位置是i,如果[0, j-1]的子串的最小的最后一个数是a,那么只要a < [j, i]的子串对应的数,那么到位置i为止的最后一个数就可以是[j, i],只要从后往前枚举j,找到的第一个满足条件a < [j, i]的j,对应的[j, i]就是要找的最小的数了,时间复杂度大概是O(n2)。
不过这还没完。“如果有多组解,使得第一个数尽量大”。。。
·第二步:
我们想要找到最大第一个数,首先就要使第二个数尽量大,然后在这之前要使第三个数尽量大,再在之前就是第四个数尽量大。。。。所以考虑从后往前找,但是直接跑一遍还是会遇到刚开始的搜索的问题(多个零导致指数级时间),比如:
1234765
最后一个数最小是765,然后往前贪心的话找到的会是最大的234,但是234被用掉之后第一个只剩下1。而我们可以发现12,34,765也是满足题意的,12显然比1大,不妥QWQ。
对于每个位置的决策,不仅仅取决于右边相邻的一个位置,还取决于右边的右边,以及右边的右边的右边……的位置。于是还是要回到动态规划上面来。重复利用之前的状态:
对于每个位置j,子串[j, N]的第一个数会有一个最大值(当然是在第一步割出最小的最后一个数之后),这个最大值可以用于更新在位置j之前的所有位置i的对应子串[i, N]的第一个数的最大值。
状态&状态转移方程见代码
时间复杂度是O(n2)
#include <bits/stdc++.h> using namespace std;
const int MAX_N = ; string s;
int a[MAX_N], len;
int st[MAX_N], ed[MAX_N];
//st 开始坐标, ed 结束坐标 bool cmp(int st1, int ed1, int st2, int ed2)
{
while (st1 <= ed1 && a[st1] == )
st1++;
while (st2 <= ed2 && a[st2] == )
st2++;
int len1 = ed1 - st1 + ;
int len2 = ed2 - st2 + ;
if (len1 < len2)
return true;
if (len1 > len2)
return false;
for (int i = ; i < len1; i++) {
if (a[st1+i] < a[st2+i])
return true;
if (a[st1+i] > a[st2+i])
return false;
}
return false;
} void dp2()
{
memset(ed, , sizeof ed);
ed[st[len]] = len;
int ind = st[len]-;
while (ind >= && !a[ind])
ed[ind--] = len;
for (int i = st[len]-; i >= ; i--) {
ed[i] = max(ed[i], i);
for (int j = st[len]-; j > i; j--)
if (cmp(i, j, j+, ed[j+])) {
ed[i] = max(ed[i], j);
break;
}
}
} void dp()
{
st[] = ;
for (int i = ; i <= len; i++) {
st[i] = ;
for (int j = i; j >= ; j--)
if (cmp(st[j-], j-, j, i)) {
st[i] = j;
break;
}
}
} int main()
{
cin >> s;
len = s.size();
for (int i = ; i < len; i++)
a[i+] = s[i] - '';
dp();
dp2();
bool firstprint = true;
for (int i = ; i <= len; i++) {
if (firstprint)
firstprint = false;
else
putchar(',');
for (int j = i; j <= ed[i]; j++) {
putchar(s[j-]);
}
i = ed[i];
}
cout << endl;
return ;
}
洛谷P1415 拆分数列(dp)的更多相关文章
- 洛谷P1415 拆分数列[序列DP 状态 打印]
题目背景 [为了响应党中央勤节俭.反铺张的精神,题目背景描述故事部分略去^-^] 题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输出使得最后一个数最小的同时 ...
- 洛谷 P1415 拆分数列 解题报告
拆分数列 题目背景 [为了响应党中央勤节俭.反铺张的精神,题目背景描述故事部分略去^-^] 题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数. 如果有多组解,则输出使得最后一个 ...
- 洛谷P1415 拆分数列
题目背景 [为了响应党中央勤节俭.反铺张的精神,题目背景描述故事部分略去^-^] 题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输出使得最后一个数最小的同时 ...
- 洛谷P4063 [JXOI2017]数列(dp)
题意 题目链接 Sol 这题想还是不难想的,就是写起来很麻烦,然后去看了一下loj的最短代码表示只能Orz 首先不难发现一条性质:能够选择的区间一定是不断收缩的,而且新的可选区间一定是旧区间的某个位置 ...
- P1415 拆分数列 DP
传送门: 题意: 将一个数字串分成许多不同的小串,使得这些小串代表的数字严格递增,要求最后一个数字尽可能地小. 然后满足字典序尽可能大. 思路: 由于最后一个数字要尽可能地小,所以先处理出每个数的L[ ...
- 洛谷P1108 低价购买[DP | LIS方案数]
题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...
- NOIP2017提高组Day2T2 宝藏 洛谷P3959 状压dp
原文链接https://www.cnblogs.com/zhouzhendong/p/9261079.html 题目传送门 - 洛谷P3959 题目传送门 - Vijos P2032 题意 给定一个 ...
- 洛谷P1244 青蛙过河 DP/思路
又是一道奇奇怪怪的DP(其实是思路题). 原文戳>>https://www.luogu.org/problem/show?pid=1244<< 这题的意思给的挺模糊,需要一定的 ...
- 洛谷P3928 Sequence2(dp,线段树)
题目链接: 洛谷 题目大意在描述底下有.此处不赘述. 明显是个类似于LIS的dp. 令 $dp[i][j]$ 表示: $j=1$ 时表示已经处理了 $i$ 个数,上一个选的数来自序列 $A[0]$ 的 ...
随机推荐
- weblogic安装教程(以weblogic 11g为例)
1.下载jdk和weblogic安装介质 一般的搭配是jdk1.5+weblogic92.jdk1.6+weblogic11g(weblogic10.3.6) jdk历史版本下载链接:http://w ...
- ASP.NET Core Web 项目 发布的IIS7提示“HTTP Error 502.5 - Process Failure
原因就是NUGET引用的DLL和SDK的版本不对, 你打开CMD,在项目bin目录运行dotnet xxx.dll, 会看到具体错误信息 所以你要么引用低版本的dll,要么升级最新SDK
- LaTeX技巧10:LaTeX数学公式输入初级入门
LaTeX最强大的功能就是显示美丽的数学公式,下面我们来看这些公式是怎么实现的. 1.数学公式的前后要加上 $ 或 \( 和 \),比如:$f(x) = 3x + 7$ 和 \(f(x) = 3x + ...
- python 内置函数源码查看
如果是用python 实现的模块可以直接在IDE里面追踪到源码 也可以使用help内置函数,例如: help(os) 如果是c 语言实现的模块,则不能直接在IDE里面查看,如果直接在IDE里面查看,会 ...
- .clearfix:after(清除浮动)中各个属性及值详细解说
清除浮动.clearfix:after一词,从事web前端的朋友们对此不会陌生吧,下面为大家介绍的是.clearfix:after中用到的所有属性及值的含义,对此感兴趣的朋友可以参考下哈想,希望对大家 ...
- 计算机基础part1
一:计算机的基本组成 1.计算机由输入单元.控制单元.算法逻辑单元.输出单元.存储单元,五大单元组成 二:概念篇 CPU:中央处理器,其内含有指令集(取码-解码-执行的过程) CPU同一时刻只能干一件 ...
- 使用MYSQL数据库实现编程----第二章第三章课堂知识小总结
第二章1:创建数据库create database myschool 2.数据类型 1.整型 int 2.小数 double 精确度要求高的 ----Decimal(18,4) 2222222 ...
- python中的各种模块(np,os,shutill)
PS:本博文摘抄自中国慕课大学上的课程<Python数据分析与展示>,推荐刚入门的同学去学习,这是非常好的入门视频. #np模块 .ndim :维度 .shape :各维度的尺度 (2,5 ...
- Linux如何从零开始搭建nfs服务器(centOS6)
Server端 1.打印系统版本 cat /etc/redhat-release uname -r uname -m 2.检查是否安装NFS服务 rpm -aq nfs-utils rpcbind L ...
- windows剪贴板
0x01 Windows剪贴板 Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制.Windows系统支持剪贴板IP ...