POJ1239 dp (严格递增子序列)

98 篇文章 1 订阅

字符串的前缀后缀处理,严格递增子序列

题意:

题目要求在整个是递增子序列的前提下最后一个元素的值要最小,并且在此前提下第一个的值要最大.

思路:

很奇怪的问题,但是细细想来就是要求我们找到严格递增的的序列,可是有两个限制,我们知道如果dp[i]定义为从第i个之前的dp[i]个数字组成的数字满足递增,这种定义方式必然导致从前往后遍历,这会导致每一个递增的数列都是尽可能的小。如此一来,其实就已经得到了最小的最后一个数字,那么我们再从后往前遍历就会得到想要的答案。

第二次dp[i] 表示的是从第i个数字开始往后的dp[i]个数字组成的数字满足严格递增的条件。

那么问提示如何dp呢?

对于第一次,根据其定义的意义,就从第 i 个数字开始,我们逐次增加长度,找打满足条件的就break

对于第二次,根据其定义的意义,若想得到比较大的数字,就从大的区间开始找。

  • 比较需要注意的是:题目不要求输出最长的,只要求输出满足连个条件的。
  • 此题很好的是考验到了,对dp 的定义,是从哪里开始切入的

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 100;

int dp[maxn];
char s[maxn];

int judge(int x1,int y1,int x2,int y2)
{
    while(s[x1] == '0' && x1 <= y1) x1++;
    while(s[x2] == '0' && x2 <= y2) x2++;
    if(x1 > y1) return false;
    if(x2 > y2) return true;
    if(y1 - x1 > y2 - x2) return true;
    else if(y2 - x2 > y1 - x1) return false;
    else {
        while(x1 <= y1) {
            if(s[x1] > s[x2]) return true;
            else if(s[x2] > s[x1]) return false;
            x1++,x2++;
        }
    }
    return false;
}

int main(int argc, char const *argv[])
{
    freopen("in.txt","r",stdin);

    while(scanf("%s",s+1) != EOF) {
        int len = strlen(s+1);
        if(s[1] == '0' && len == 1) break;
        memset(dp,0,sizeof(dp));
        dp[1] = 1;
        for (int i = 2; i <= len; ++i) {
            dp[i] = i;
            for(int j = i - 1;j >= 1; j--) {
                if(judge(j+1,i,j-dp[j]+1,j)) {
                    dp[i] = i - j;
                    break;
                }
            }
        }
        int lsatNumberStart = len - dp[len] + 1;
        dp[lsatNumberStart] = dp[len];
        for(int i = lsatNumberStart-1;i >= 1; i--) {
            if(s[i] == '0') {
                dp[i] = dp[i+1] + 1;
                continue;
            }
            for(int j = lsatNumberStart;j >= 1; j--) {
                if(judge(j,j+dp[j]-1,i,j-1)) {
                    dp[i] = j - i;
                    break;
                }
            }
        }
        for(int i = 1;i <= dp[1]; i++) {
            printf("%c",s[i]);
        }
        int t = dp[1] + 1;
        while(t <= len) {
            printf(",");
            for(int i = t;i < t + dp[t]; i++)
                printf("%c",s[i]);
            t = t + dp[t];
        }
        printf("\n");
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值