首页 > 试题广场 >

CCNumber

[编程题]CCNumber
  • 热度指数:845 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
CC最近对一种整数比较感兴趣,我们暂且把这种整数称为C Number, C Number是指一个整数  {C0, C1 … Cn-1} (C0 > 0 , n >= 3), 存在一个Cm(0<m<n-1)满足以下条件:
    Ci-1 < Ci (0<i<=m), Ci代表这个整数中的第i位数字
    Ci>Ci+1(m<=i<n-1)
    如果一个整数里面有相邻的2个C Number的话,我们称这个整数为CC Number(2个C Number不可以有公用的数字Ci,并且2个C Number要紧紧相邻)。
    请在[A,B]区间内找出找出score最大的CCNumber 并输出这个score.(score:CC Number中所有数字的和)

输入描述:
第一行为数字N(N<=1000),后面有N行测试用例
每行用例有2个数字 A,B(0<=A<=B<2^64),需要[A,B]区间内找出题干中描述的最大score。


输出描述:
对于第N行的测试用例,输出“Case N: S”, S为最大的score,如果区间内没有CC Number的话 S为0。
示例1

输入

4
12121 12121
120010 120010
121121 121121
1211121 1211121

输出

Case 1: 0
Case 2: 0
Case 3: 8
Case 4: 0
12121 12121    cNumber有两个121 121,但是两个cNumber有公用的1,因此不是CCNumber;
120010 120010  cNumber只有一个120,由于010不是整数所以不能算,因此也不是CCNumber;
121121 121121  cNumber有两个121 121,并且相邻,所以是CCNumber,score=1+2+1+1+2+1=8;
1211121 1211121  同上两个Cnumber,但是不相邻,所以不是CCNumber
是这样理解的,但是编程之后只过了20%,显示超时,求大佬解决

发表于 2019-08-31 11:34:14 回复(1)
代码写的有点乱,解释下我的思路
先解释下题意,CNumber就是一个类似尖角形状的整数,先增后减,第一个数字不能是0,长度大于等于3,CCNumber是可以拆分成两个CCNumber的整数,注意是拆分,而不是包含,两部分不能重合,就是左半边是个尖角,右边也是尖角。
举例:
CNumber:   121      123454321
CCNumber:          121121   121123454321
思路:
通过将[A,B]区间分割成更小的区间 ,当小区间的上界和下界变成
公共前缀99..99
公共前缀00..00
这样的形式时,前缀部分固定了,后面部分可任选,找出这种情况下是CCNumber且Score最大的情况,所有区间的最大值就是答案。

问题变成两部分:区间分割、求解固定形式的区间的最大Score

区间分割:
先把A用0扩充与B同等长度,然后开始从高到低一位一位的比较,
如果B[k]==A[k],比较下一位
B[k]=A[k]+1,就可以将区间分割成两段,
        [前k-1位公共前缀      bk  00..00]   -   B    
        A  -     [前k-1位公共前缀         bk-1 99..99]
Bk>A[k]+1
除了上面两部分就可以多分出一部分区间(此处省略不显示公共前缀)
[bk-1     00..00]-[bk-1  99..99]
[bk-2     00..00]-[bk-2  99..99]
....
[ak+1     00..00]-[ak+1  99..99]
这些区间就可以直接计算了

举例
[000000-123456]
分为100000 - 123456                  000000-099999
100000 - 123456 分为
120000-123456       100000-109999     以及110000-119999 可以计算
120000-123456分为
123000-123456    120000-120999   以及121000-121999  122000-122999


求解固定格式的区间解:
当0-9可以任选时,为了使用Score最大,在满足增或减条件下数字能从大就从大取,如前缀是121时,给它补个898;
            当前缀固定时,如何根据后面的几个任意数字(癞子)来凑出最大Score,需要根据前缀所处的阶段,如果前缀已经处于第二个尖角的下降状态,当然就只能补比它小的数,一路补到0
           
 具体补法:根据公共前缀末尾数字所处阶段(遍历根据增/减情况判断出)
估计后面位置上,所有可能数字出现的次数,然后依次从大到小开始取这些数字直到癞子数为0

                如121     它现在是处于第一个序列的末尾,还可能出现一个增序列一个减序列,所以2-8可能出现的次数是2   9出现的次数是1      
                从9开始取
                癞子数为3时      补898
                4时                    补8987



预先将所有阶段 当数字以及癞子数确定 时的最大Score 计算出来以加快计算。
T[i][j][k]是第i阶段数字为j时 有k个任意数字能凑出的最大Score值,T_s是对应的凑出的整数部分

编辑于 2020-02-19 17:15:44 回复(0)
原谅我,题目看了n多遍,还是一头雾水
发表于 2019-07-19 13:58:16 回复(0)
看不懂题目加一,啥叫相邻的两个C number,按那个C number条件怎么可能相邻呢,不懂
发表于 2019-08-07 19:19:14 回复(0)
贡献一个数位dp的题解,代码量小一些,但是比大佬们写的几百行的代码要慢几十ms。状态转移和大佬们的代码的思路是一致的,不知道为什么慢一点。如果有还能优化之处,欢迎赐教。
#include<bits/stdc++.h>

using namespace std;
int a[22], b[22], la, lb;
const int inf = 0x3f3f3f3f;
//f1 -> a  f2 -> b 
//0->        , 第一座山开始之前
//1 -> _      , 第一座山的山脚
//2 -> _/     , 上坡
//3 -> _/\    , 下坡 
//4 -> _/\_   , 第二座山的山脚
//5 -> _/\_/  , 上坡
//6 -> _/\_/\ , 下坡

int dp[22][11][7][2][2]{}; //dp[cur][n][state][f1][f2]
int dfs(int cur, int n, int state, bool f1, bool f2){
//cur当前所处的第几位数 n前一个数, state前一个数所处的状态, f1下限标志, f2上限标志
    auto &h = dp[cur+1][n+1][state][f1][f2];
    if(cur == -1) {
        if(state == 6) return h = 0;
        else return h = -1;//非法
    }
    if(h != inf) return h;
    h = -1;
    int s = f1?a[cur]:0, e = f2?b[cur]:9, t;
    if(state == 0){//代表开始之前的状态,可以任意取值,不要忘了C0>0
        for(int i = max(1, s); i <= e; ++i){//开启第一座山
            t = dfs(cur - 1, i, state+1, f1&&i==a[cur], f2&&i==b[cur]);//进入山脚
            if(t != -1) h = max(h, t + i);
        }
        if(s==0){//当前位为0,不开启第一座山,继续下一位
            t = dfs(cur - 1, -1, state, f1&&0==a[cur], f2&&0==b[cur]);
            if(t != -1) h = max(h, t);
        }
    }
    else if(state == 2||state ==5){//正在上坡
        for(int i = s; i <= min(n-1, e); ++i){
            t = dfs(cur - 1, i, state+1, f1&&i==a[cur], f2&&i==b[cur]);//上坡转下坡
            if(t != -1) h = max(h, t + i);
        }
        for(int i = max(n+1, s); i <= e; ++i){
            t = dfs(cur - 1, i, state, f1&&i==a[cur], f2&&i==b[cur]);//继续上坡
            if(t != -1) h = max(h, t + i);
        }
    }
    else if(state == 1||state==4){
        //山脚处必须上升
        for(int i = max(n + 1, s); i <= e; ++i){
            t = dfs(cur - 1, i, state+1, f1&&i==a[cur], f2&&i==b[cur]);
            if(t != -1) h = max(h, t + i);
        }
    }
    else if(state == 6 || state == 3){
        for(int i = s; i <= min(n-1, e); ++i){
            t = dfs(cur - 1, i, state, f1&&i==a[cur], f2&&i==b[cur]);//继续下坡
            if(t != -1) h = max(h, t + i);
        }
    }
    if(state == 3){//结束第一座山,i作为第二座山的山脚,别忘了C0>0
        for(int i = max(1,s); i <= e; ++i){
            t = dfs(cur - 1, i, state+1, f1&&i==a[cur], f2&&i==b[cur]);
            if(t != -1) h = max(h, t + i);
        }
    }
    return h;
}
int getdigits(string s, int d[]){
    int i = 0;
    for(; i < s.size(); ++i) d[i] = s[s.size() - 1 - i] - '0';
    return i;
}
int main(){
    int N;
    long long A, B;
    scanf("%d", &N);
    for(int i = 0; i < N; ++i){
        memset(dp, 0x3f3f3f3f, sizeof dp);
        memset(a, 0, sizeof a);
        memset(b, 0, sizeof b);
        string sa, sb;
        cin >> sa >> sb;
        la = getdigits(sa, a), lb = getdigits(sb, b);
        int ret = dfs(lb - 1, -1, 0, true, true);
        printf("Case %d: %d\n", i+1, ret == -1 ? 0 : ret);
    }
    return 0;
}


编辑于 2020-03-17 01:06:01 回复(0)
n = int(input())
for k in range(n):
    maxscore=0
    start, end = map(int, input().split())
    for num in range(start, end+1):
        i=0
        num=str(num)
        while i<=len(num)-6:
            if num[i]=='0' or num[i+3]=='0':
                pass
            elif num[i]<num[i+1] and num[i+1]>num[i+2]:
                if num[i+3]<num[i+4] and num[i+4]>num[i+5]:
                    s=0
                    for j in range(0,6):
                        s+=int(num[i+j])
                    maxscore=max(s,maxscore)
            i+=1
    shuchu="Case "+str(k+1)+": "+str(maxscore)
    print(shuchu)

有没有大佬来收了这道题,有的话记得@我一下。。。只能通过20%,时间复杂度过高
发表于 2019-09-10 16:33:49 回复(0)
神了,居然一个通过的都没有。。哪位大佬来收了这道题
发表于 2019-07-21 11:36:52 回复(0)