ZOJ Problem Set - 3816 Generalized Palindromic Number 搜索+贪心

A number that will be the same when it is written forwards or backwards is known as a palindromic number. For example, 1234321 is a palindromic number.

We call a number generalized palindromic number, if after merging all the consecutive same digits, the resulting number is a palindromic number. For example, 122111 is a generalized palindromic number. Because after merging, 122111 turns into 121 which is a palindromic number.

Now you are given a positive integer N, please find the largest generalized palindromic number less thanN.

Input

There are multiple test cases. The first line of input contains an integer T (about 5000) indicating the number of test cases. For each test case:

There is only one integer N (1 <= N <= 1018).

Output

For each test case, output the largest generalized palindromic number less thanN.

Sample Input
4
12
123
1224
1122
Sample Output
11
121
1221
1121

  网络赛第一场的H题,比赛的时候想前面一半应该不是相等就是减一,然后再递归去做,但是又感觉很复杂,赛后看别人的代码,有很长的,也有一种是搜索,比较短,看了后觉得这个方法挺好。

  思路是从大到小枚举左边,左边不能超过N的左边,左边枚举的当前位如果和上一位不相等,右边就也需要添加这个数,因为必须保证是这种回文串。右边添加几个呢,暴力枚举搜索所有可能个数,最后这个串的长度和N的长度相等时,把左边和右边合并,看得到的这个数是否比N小(因为左边部分不超过N的左边部分不代表左右合并的串小于N)。因为左边是从大到小枚举的,所以一旦找到符合的就返回。搜索过程中eq表示之前是否达到临界,如果达到了这一位就只能取str[l],没达到可以取9。

 

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MAXN 25
#define MAXM 200010
#define MAXNODE 50010
#define MOD 999983
#define SIGMA_SIZE 4
typedef long long LL;
using namespace std;
int T,len,lnum[MAXN],rnum[MAXN];
char str[MAXN];
LL N;
LL getnum(int l,int r){
    LL ret=0;
    for(int i=0;i<l;i++) ret=ret*10+lnum[i];
    for(int i=r-1;i>=0;i--) ret=ret*10+rnum[i];
    if(ret<N) return ret;
    return -1;
}
LL DFS(int l,int r,int eq){
    if(l+r>=len) return getnum(l,r);
    LL ret=-1;
    int m=eq?str[l]-'0':9;
    for(int i=m;i>=0;i--){
        lnum[l]=i;
        if((!l||lnum[l]!=lnum[l-1])&&(i||l)&&(l+r+1<len)){
            for(int k=1;l+r+k<=len;k++){
                rnum[r+k-1]=i;
                ret=max(ret,DFS(l+1,r+k,eq&&i==m));
            }
        }
        else ret=max(ret,DFS(l+1,r,eq&&i==m));
        if(ret!=-1) return ret;
    }
    return ret;
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&N);
        sprintf(str,"%lld",N);
        len=strlen(str);
        printf("%lld\n",DFS(0,0,1));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值