luoguP1415 拆分数列 [dp]
Posted ZYBGMZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP1415 拆分数列 [dp]相关的知识,希望对你有一定的参考价值。
题目描述
给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数。如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小;如果有多组解,则使得第一个数尽量大;如果仍有多组解,则使得第二个数尽量大,依次类推……)。
输入输出格式
输入格式:
共一行,为初始的数字。
输出格式:
共一行,为拆分之后的数列。每个数之间用逗号分隔。行尾无逗号。
输入输出样例
输入样例#1:
[1] 3456 [2] 3546 [3] 3526 [4] 0001 [5] 100000101
输出样例#1:
[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。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<string> 5 using namespace std; 6 7 const int maxn=505; 8 9 string str; 10 int a[maxn],n,dP[maxn],Dp[maxn]; 11 12 bool cmp(int l1,int r1,int l2,int r2){ 13 while(l1<=r1&&a[l1]==0) l1++; 14 while(l2<=r2&&a[l2]==0) l2++; 15 int le1=r1-l1+1,le2=r2-l2+1; 16 if(le1==0||le2==0) return 0; 17 if(le1!=le2) return le1<le2; 18 for(int i=0;i<le1;i++) 19 if(a[l1+i]!=a[l2+i]) return a[l1+i]<a[l2+i]; 20 return 0; 21 } 22 23 //dP[i]=max(j),(T(dP[j-1],j-1)<T(j,i)) 24 void DP1(){ 25 for(int i=1;i<=n;i++){ 26 dP[i]=1; 27 for(int j=i;j;j--) 28 if(cmp(dP[j-1],j-1,j,i)){ 29 dP[i]=j; 30 break; 31 } 32 // printf("dP[%d] = %d\n",i,dP[i]); 33 } 34 } 35 36 //Dp[i]=max(j) (T(i,j)<T(j+1,f[j+1])) 37 void DP2(){ 38 Dp[dP[n]]=n; 39 for(int i=dP[n];a[i-1]==0;i--) Dp[i-1]=n; 40 41 for(int i=dP[n]-1;i;i--){ 42 for(int j=dP[n]-1;j>=i;j--) 43 if(cmp(i,j,j+1,Dp[j+1])){ 44 Dp[i]=j; 45 break; 46 } 47 // printf("Dp[%d] = %d\n",i,Dp[i]); 48 } 49 } 50 51 void print(int l,int r){ 52 for(int i=l;i<=r;i++) 53 putchar(a[i]+‘0‘); 54 } 55 56 void print(){ 57 print(1,Dp[1]); 58 int pos=Dp[1]+1; 59 while(pos<=n){ 60 putchar(‘,‘); 61 print(pos,Dp[pos]); 62 pos=Dp[pos]+1; 63 } 64 } 65 66 int main(){ 67 cin>>str; n=str.length(); 68 for(int i=0;i<n;i++) a[i+1]=str[i]-‘0‘; 69 DP1(); DP2(); 70 print(); 71 return 0; 72 }
以上是关于luoguP1415 拆分数列 [dp]的主要内容,如果未能解决你的问题,请参考以下文章