这么麻烦的题敲出来没WA真的是舒服~
原题: https://www.luogu.org/problemnew/show/P1415
题意:
给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数。如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小;如果有多组解,则使得第一个数尽量大;如果仍有多组解,则使得第二个数尽量大,依次类推……)。
解析:
大小比较函数:
int compare(int ll,int rr,int l,int r){
while(ll<rr&&x[ll]=='0')ll++;
while(l<r&&x[l]=='0')l++;
if(rr-ll>r-l)return 1;
if(rr-ll<r-l)return -1;
for(;ll<=rr;ll++,l++){
if(x[ll]>x[l])return 1;
if(x[ll]<x[l])return -1;
}
return 0;
}
第一要求最后一个数最小,那么先从后往前,得到一个最小的满足要求的段。这个段只要可以做到满足要求,那么答案段就是这个。(这个串的前面可能有前缀0)
这个过程需要用到记忆化搜索,即L~R这个区间可能被搜索多次,如果这个区间不能达到要求,那么标记-剪枝。
找到最后一段后,再要求前面的数大。那么枚举从大开始,1~L-1
到1~1
,如果满足要求则打标记,ans[i]=1表示第i个字母后面插逗号。
往后搜的过程也需要记忆化搜索-打标记,我第一发忘记vis[l][r]=1;
就TLE了。
细节:
- 一个段全是0也判不符合,要求打标记。
- 最后一段L==1则直接输出即可。
- 最后一段L前面可能有前缀0,所以往后搜的结束标志为:右边界落在为0的那个区间内。
#include<bits/stdc++.h>
using namespace std;
char x[509];
int len;
int compare(int ll,int rr,int l,int r){
while(ll<rr&&x[ll]=='0')ll++;
while(l<r&&x[l]=='0')l++;
if(rr-ll>r-l)return 1;
if(rr-ll<r-l)return -1;
for(;ll<=rr;ll++,l++){
if(x[ll]>x[l])return 1;
if(x[ll]<x[l])return -1;
}
return 0;
}
bool isempty(int l,int r){
for(int i=l;i<=r;i++)if(x[i]!='0')return 0;
return 1;
}
bool vis[509][509];//记忆化
bool check(int L,int R){
if(isempty(L,R)){vis[L][R]=1;return 0;}
if(L==1)return true;
for(int i=L-1;i>=1;i--){
if(vis[i][L-1])continue;
if(compare(i,L-1,L,R)<0){
if(check(i,L-1))return 1;
}
else break;//数变大就更不行了
}
vis[L][R]=1;//标记
return 0;
}
int L,LL;
bool ans[509];
bool check2(int l,int r){
if(vis[l][r])return 0;
if(isempty(l,r)){vis[l][r]=1;return 0;}
if(compare(l,r,L,len)>=0){vis[l][r]=1; return 0;}
//搜索结束
if(r>=LL-1&&r<=L-1){ans[r]=1;return 1;}
for(int i=L-1;i>r;i--){
if(compare(r+1,i,L,len)>=0){
vis[r+1][i]=1;continue;
}
if(compare(r+1,i,l,r)<=0)continue;
if(check2(r+1,i)){
ans[i]=1;return 1;
}
}
vis[l][r]=1;//标记
return 0;
}
int main(){
scanf("%s",x+1);
len=strlen(x+1);
L=1;
for(L=len;L>=1;L--){
if(check(L,len)){break;}
}
if(L==1)return 0*printf("%s\n",x+1);
LL=L;while(LL>1&&x[LL-1]=='0')LL--;
memset(vis,0,sizeof(vis));
for(int i=L-1;i>=1;i--){
if(check2(1,i)){
ans[i]=1;break;
}
}
for(int i=1;i<=len;i++){
printf("%c",x[i]);
if(ans[i])printf("%c",',');
}
printf("\n");
}