数位DP—— GDUT 等凹数字

  • 题目链接: http://gdutcode.sinaapp.com/problem.php?cid=1057&pid=6

  • 题意:求出区间内等凹数字的个数,等凹数字:定义一种数字称为等凹数字,即从高位到地位,每一位的数字先非递增再非递减,不能全部数字一样,且该数是一个回文数,即从左读到右与从右读到左是一样的,仅形成一个等凹峰。

  • 分析:解析一个等凹数字需要满足的条件:必须下降过,必须上升过,必须是回文。那么我们就可以定义出前缀的状态:剩下数位,等凹数长度,前缀末尾的数字,前缀是否下降过,前缀是否上升过,前缀是否为回文。然后搜索出所有前缀含有的等凹数的数量。

  • AC代码:

/*************************************************************************
    > File Name: test.cpp
    > Author: Akira 
    > Mail: [email protected] 
 ************************************************************************/

#include
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;

#define MaxN 100001
#define MaxM MaxN*10
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
const int mod = 1E9+7;
const double eps = 1e-6;
#define bug cout<<88888888<
#define debug(x) cout << #x" = " << x<
int T;
LL L,R;
int digits[20];
int num[20];
LL DP[20][20][10][2][2][2];
LL dfs(int pos, int len, int pre, bool up, bool down, bool ispa, bool zero, bool limit)
{
    if(pos==0) return up&&down&&ispa;
    if(!limit && DP[pos][len][pre][up][down][ispa]!=-1) return DP[pos][len][pre][up][down][ispa];
    LL ans = 0;
    int Max = limit ? digits[pos] : 9;
    for(int i=0;i<=Max;i++)
    {
        num[pos] = i; //深搜路上记录每次选择的数字
        if(zero) ans += dfs(pos-1, len-(i==0), i, 0, 0, ispa, (i==0), limit&&i==Max);
        else if(i==pre)
        {
            if(ispa&&pos<=len/2) ans += dfs(pos-1,len,i,up,down,i==num[len+1-pos],zero,limit&&i==Max);
            else ans += dfs(pos-1,len,i,up,down,ispa,zero,limit&&i==Max);
        }
        else if(iif(up) continue;    //如果上升过,就不能下降
            if(ispa&&pos<=len/2) ans += dfs(pos-1,len,i,up,true,i==num[len+1-pos],zero,limit&&i==Max);
            else ans += dfs(pos-1,len,i,up,true,ispa,zero,limit&&i==Max);
        }
        else if(i>pre)
        {
            if(!down) continue; //如果没有下降过,不能上升
            if(ispa&&pos<=len/2) ans += dfs(pos-1,len,i,true,down,i==num[len+1-pos],zero,limit&&i==Max);
            else ans += dfs(pos-1,len,i,true,down,ispa,zero,limit&&i==Max);
        }
    }
    if(!limit) DP[pos][len][pre][up][down][ispa]=ans;
    return ans;
}

LL find(LL x)
{
    int pos = 0;
    while(x)
    {
        digits[++pos] = x%10;
        x/=10;
    }
    return dfs(pos,pos,0,false,false,true,true,true);
}

void solve()
{
    printf("%lld\n", find(R)-find(L-1));
}
void init()
{
    MST(DP,-1);
}
int main()
{
    init();
    //std::ios::sync_with_stdio(false);
    scanf("%d", &T);
    while(T--)
    {
        scanf("%lld%lld", &L, &R);
        solve();
    }
    //system("pause");
}

你可能感兴趣的:(ACM算法(题解):,动态规划,——数位DP)