数位dp 等凹数字 (未完成)

本文介绍了一种算法,用于计算指定区间内等凹数字的数量。等凹数字是指其数字序列先非递增后非递减,并且是回文数的整数。文章提供了两段代码实现,详细展示了如何通过动态规划解决这一问题。

广工校赛
Problem G: 等凹数字
Description
定义一种数字称为等凹数字,即从高位到地位,每一位的数字先非递增再非递减,不能全部数字一样,且该数是一个回文数,即从左读到右与从右读到左是一样的,仅形成一个等凹峰,如543212345,5544334455是合法的等凹数字,543212346,123321,111111不是等凹数字。现在问你[L,R]中有多少等凹数字呢?

Input
第一行一个整数T,表示数据的组数。

接下来T行每行俩个数字L和R,(1<=L<=R<=1e18)

Output
输出一个整数,代表[L,R]中有多少等凹数字

Sample Input
2
1 100
101 200
Sample Output
0
1
HINT
小于等于2位的数字无凹峰

//太坑了,只会套模板,这个地方不知道怎么修改成”凹峰“会错。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<stack>
#include<cmath>
#include<map>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define bug1 cout<<"bug1"<<endl;
#define bug2 cout<<"bug2"<<endl;
#define bug3 cout<<"bug3"<<endl;
using namespace std;
int dig[30];
int tmp[30];
int dp[30][30][2];
int dfs(int pos,int start,int flag,bool limit){
    if(pos<0){
        int flagsame=1;
        for(int i=1;i<=start;++i){
            if(tmp[i]!=tmp[i-1]){
                flagsame=0;break;
            }
        }

        if(flagsame||flagup)return 0;
        else return flag;

    }
    if(!limit&&dp[start][pos][flag]!=-1)return dp[start][pos][flag];
    int up=limit?dig[pos]:9;
    int ret=0;
    for(int i=0;i<=up;++i){
/*
        if(pos>=(1+start)/2){
            int flagde=0;
            for(int j=start;j>=pos;--j){
                if(tmp[j]<i){
                    flagde=1;break;
                }
            }
            if(flagde)continue;
        }
        bug1
*/
        tmp[pos]=i;
        if(start==pos&&i==0){
            ret+=dfs(pos-1,start-1,flag,limit&&dig[pos]==i);
        }
        else if(flag==1&&pos<(1+start)/2){
            ret+=dfs(pos-1,start,tmp[pos]==tmp[start-pos],limit&&dig[pos]==i);
        }
        else{
            ret+=dfs(pos-1,start,flag,limit&&dig[pos]==i);
        }
    }
    if(!limit)dp[start][pos][flag]=ret;
    return ret;
}
int solve(ll x){
    memset(dig,0,sizeof(dig));
    int tol=0;
    while(x){
        dig[tol++]=x%10;
        x/=10;
    }
    return dfs(tol-1,tol-1,1,true);
}
int main(){
    int t;
    scanf("%d",&t);
    int _case=0;
    memset(dp,-1,sizeof(dp));
    solve(1e18);
    while(t--){
        ll a,b;
        scanf("%lld%lld",&a,&b);
        if(a>b)swap(a,b);
        printf("Case %d: %d\n",++_case,solve(b)-solve(a-1));
    }
}
标程,,还没看201733113:20:38
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <time.h>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
long long dp[20][20][10][2][2][2];
int num[20];
int s[20];
long long rec(int i,int pre,int up,int down,int flag,int q,int len,int ispa)
{
    if(i<0)return up&&down&&ispa;
    if(~dp[i][len][pre][up][down][ispa]&&!flag&&!q)return dp[i][len][pre][up][down][ispa];
    long long res=0;
    int o=s[i];
    for(int j=0;j<10;j++)
    {
        num[i]=j;
        if(j>o&&flag)break;
        if(q)res+=rec(i-1,j,0,0,j<o?0:flag,q&&j==0,len-(q&&j==0),ispa);
        else if(j==pre)
        {
            if(ispa&&i<len/2)
            res+=rec(i-1,j,up,down,j<o?0:flag,q&&j==0,len,j==num[len-i-1]);
            else res+=rec(i-1,j,up,down,j<o?0:flag,q&&j==0,len,ispa);
        }
        else if(j>pre)
        {
            if(!down)continue;
            if(ispa&&i<len/2)
            res+=rec(i-1,j,1,down,j<o?0:flag,q&&j==0,len,j==num[len-i-1]);
            else res+=rec(i-1,j,1,down,j<o?0:flag,q&&j==0,len,ispa);
        }
        else if(j<pre)
        {
            if(up)continue;
            if(ispa&&i<len/2)
            res+=rec(i-1,j,up,1,j<o?0:flag,q&&j==0,len,j==num[len-i-1]);
            else res+=rec(i-1,j,up,1,j<o?0:flag,q&&j==0,len,ispa);
        }
    }
    if(!flag&&!q)dp[i][len][pre][up][down][ispa]=res;
    return res;
}
long long cal(long long x)
{
    int len=0;
    while(x)
    {
        s[len++]=x%10;
        x/=10;
    }
    return rec(len-1,0,0,0,1,1,len,1);
}
int main()
{
    memset(dp,-1,sizeof(dp));
    long long l,r;
    int t;
    scanf("%d",&t);
    while(t--){
    scanf("%lld%lld",&l,&r);
    printf("%lld\n",cal(r)-cal(l-1));
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值