【转】ZOJ 3816 (伪数位dp+剪枝)||贪心

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 50;
int lim[maxn], len;
LL num;
void getlim(LL n) {
    memset(lim, 0, sizeof(lim));
    len = 0;
    while (n) {
        lim[len++] = n % 10;
        n /= 10;
    }
}
int tmp[maxn];
bool ok(int len,int rlen) {
    int l = 0, r = len - 1;
    while (l <= r) {
        if (tmp[l] != tmp[r] && r < rlen) return false;
        l++; r--;
    }
    return true;
}
LL dfs(int now, int pos, bool bound, bool first, LL num) {
    if (now == 0) {
        if (ok(pos,pos)) return num;
        else return 0;
    }
    bool can = false;
    for (int j = pos; j <= pos + now; j++) {
        if (ok(j, pos)) {
            can = true; break;
        }
    }
    if (!can) return 0;
    int m = bound ? lim[now - 1] : 9;
    for (int i = m; i >= 0; i--) {
        LL ret;
        int npos = pos;
        if (first || i) {
            if (pos == 0) tmp[pos] = i, npos = 1;
            else {
                if (i != tmp[pos - 1]) {
                    tmp[pos] = i;
                    npos = pos + 1;
                }
                else npos = pos;
            }
        }
        if (i) ret = dfs(now - 1, npos, bound && i == m, true, num * 10 + i);
        else ret = dfs(now - 1, npos, bound && i == m, false, num * 10 + i);
        if (ret) return ret;
    }
    return 0;
}
int main() {
    memset(f, -1, sizeof(f));
    int T; scanf("%d", &T);
    while (T--) {
        scanf("%lld", &num);
        getlim(num - 1);
        printf("%lld\n", dfs(len, 0, 1, 0, 0));
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#define pb push_back
#define mp make_pair
#define eps 1e-9
#define zero(x) (fabs(x)<eps)
#define pi acos(-1.0)
#define f1 first
#define f2 second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define initial 1,n,1
const int inf=0x3f3f3f3f;
const long long INF=1LL<<50;
using namespace std;
typedef long long LL;
typedef pair <int, int> PII;
template<typename X> inline bool minimize(X&p,X q){if(p<=q)return 0;p=q;return 1;}
template<typename X> inline bool maximize(X&p,X q){if(p>=q)return 0;p=q;return 1;}
int a[20],b[20],prel[20],canp[20],p1[20],p2[20];
bool ok[20][20];
LL yuan[20],pre[20],n;
int len;
void pree()
{
    memset(canp,0,sizeof(canp));
    a[0]=-1;pre[0]=0; prel[0]=0;
    for (int i=1;i<=len;i++)
      if (a[i]==a[i-1]) {pre[i]=pre[i-1];        prel[i]=prel[i-1];   canp[i]=0; }
                   else {pre[i]=pre[i-1]*10+a[i];prel[i]=prel[i-1]+1; canp[i]=1; }

}
void preok()
{
    for (int i=1;i<=len;i++)
    for (int j=i;j<=len;j++)
        {   int pp=0,last=-1;
            for (int k=i;k<=j;k++)
                {
                    if (last!=a[k]) {p1[++pp]=a[k];last=a[k];}
                }
            for (int k=1;k<=pp;k++)
                p2[k]=p1[pp+1-k];
            ok[i][j]=1;
            for (int k=1;k<=pp;k++)
                if (p1[k]!=p2[k]) {ok[i][j]=0;break;}
        }
}
void doit()
{   scanf("%lld",&n);
    if (n==1)
        {
            printf("%d\n",0);return;
        }
    LL x=n;len=0;
    while (x)
        {   len++;
            a[len]=x%10;
            x/=10;
        }
    for (int i=1;i<=len;i++)
        b[i]=a[len+1-i];
    yuan[0]=0;
    for (int i=1;i<=len;i++)
        {a[i]=b[i];
         yuan[i]=yuan[i-1]*10+a[i];
        }
    pree();
    preok();


    for (int i=len;i>=1;i--)
    for (int j=a[i]-1;j>=0;j--)
        {   //printf("\t\t\t%d %d\n",i,j);
            if (i==1&&j==0)continue;
            a[i]=j;
            if (a[i]==a[i-1]) {pre[i]=pre[i-1];        prel[i]=prel[i-1];   canp[i]=0;   }
                         else {pre[i]=pre[i-1]*10+a[i];prel[i]=prel[i-1]+1; canp[i]=1;   }

            yuan[i]=yuan[i-1]*10+a[i];
            LL ans=0;
            if (len-i>=prel[i])
                {   LL tmp=yuan[i],tt=pre[i];
                    int shouldadd=len-i-prel[i],now;
                    for (int z=1;z<=shouldadd;z++)
                        tmp=tmp*10+9;
                    while (tt)
                            {   now=tt%10;
                                tmp=tmp*10+now;
                                tt/=10;
                            }
                    ans=max(ans,tmp);
                }
            if (len-i+1==prel[i])
                {   LL tmp=yuan[i],tt=pre[i];
                    int now;
                    tt/=10;
                    while (tt)
                            {   now=tt%10;
                                tmp=tmp*10+now;
                                tt/=10;
                            }
                    ans=max(ans,tmp);

                }

            for (int k=i;k>=1;k--)
            if (a[k]==j&&prel[k]<=len-i+1&&canp[k])
                {
                    int kk=k;while (a[kk]==a[kk+1]&&kk<i)kk++;
                    int ii=i;while (a[ii]==a[ii-1]&&ii>k)ii--;
                    kk++;ii--;
                    if (kk<=ii&&!ok[kk][ii]) continue;

                    LL tt=pre[k],tmp=yuan[i-1];
                    int shouldadd=len-i+1-prel[k],yyy=-1,yl=0,have=0,now;

                    while (tt)
                         {
                            if (tt%10<yl) {yyy=yl; break;}
                            yl=tt%10;
                            tt/=10;
                         }
                    if (yyy==-1) yyy=yl;
                    tt=pre[k];
                    while (tt)
                            {   now=tt%10;
                                tmp=tmp*10+now;
                                if (!have&&yyy==now)
                                {   for (int z=1;z<=shouldadd;z++)
                                        tmp=tmp*10+now;
                                    have=1;
                                }
                                tt/=10;
                            }
                    ans=max(ans,tmp);
                }

            if (ans!=0) {printf("%lld\n",ans);return;}
        }
        for (int i=len-1;i>=1;i--)
            printf("%d",9);printf("\n");
}
int main()
{

    int cas;
    scanf("%d",&cas);
    while (cas--) doit();
}

/*
1
1020
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值