递增序列
递增序列
时间限制: 1 Sec 内存限制: 128 MB题目描述
给定一个数字串,请你插入若干个逗号,使得该数字串成为一个严格递增的数列且最后一个数要尽可能小,在这个问题中,前导的零是允许出现在数的前面的。
输入
输入数据仅含一行,为一个长度不超过 80 的数字串。
输出
输出一个严格递增且最后一数最小的数列,相邻两个数之间用一个逗号隔开,如果有多个数列满足要求,则输出第一个数最大的那个数列,若这样的解还不止一个,则输出第二个数最大的那个数列,以此类推。
样例输入
100000101
样例输出
100,000101
题解:
dp[i]表示i位以前所有分法中能使最后一个数最小的最后一个数的下标,f[i]表示从后往前能使最前面一个数最大的最前面一个数的下标。
dp[i]表示i位以前所有分法中能使最后一个数最小的最后一个数的下标,f[i]表示从后往前能使最前面一个数最大的最前面一个数的下标。
先动归dp[i],保证最后一个数最小,再动归f[i],保证前面的数最大。由此而来即是最优解。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<stack> #include<ctime> #include<vector> using namespace std; int n,dp[120],f[120],ans[120],cnt; char s[120]; int cmp(int l,int r,int ll,int rr) { while(s[l]=='0'&&l+1<=r)l++; while(s[ll]=='0'&&ll+1<=rr)ll++; int len1=r-l+1,len2=rr-ll+1; if(len1>len2)return 1; else if(len1<len2)return -1; else { while(l+1<=r&&ll+1<=rr&&s[l]==s[ll]) { l++; ll++; } if(s[l]>s[ll])return 1; if(s[l]<s[ll])return -1; } return 0; } int main() { int i,j; scanf("%s",s); n=strlen(s); dp[0]=0; for(i=1; i<n; i++) { for(j=i-1; j>=0; j--) { if(cmp(dp[j],j,j+1,i)<0) { dp[i]=j+1; break; } } } f[dp[n-1]]=n-1; int k=dp[n-1]-1; while(s[k]=='0') { f[k]=n-1; k--; } for(i=k; i>=0; i--) { for(j=dp[n-1]; j>=i+1; j--) { if(cmp(i,j-1,j,f[j])<0) { f[i]=j-1; break; } } } i=0; while(1) { int l=i; i=f[i]; for(j=l;j<=i;j++) cout<<s[j]; i++; if(i==n)break; cout<<','; } return 0; }