P1831 杠杆数(数位Dp)

题目描述

如果把一个数的某一位当成支点,且左边的数字到这个点的力矩和等于右边的数字到这个点的力矩和,那么这个数就可以被叫成杠杆数。

比如$4139$就是杠杆数,把3当成支点,我们有这样的等式:$4 \times 2 + 1\times 1 = 9 \times 1$。

给定区间$[x,y]$,求出在$[x,y]$中有几个杠杆数。

输入格式

两个数,表示$x,y$。

输出格式

一个输出,表示区间$[x,y]$中杠杆数的个数。

样例数据

输入

7604 24324

输出

897

分析

求$[1,x]$这个区间内符合条件的数的个数。因为$[x,y]$中符合条件的个数可以转化为$[1,y]$区间内的个数减去$[1,x-1]$区间内的个数,然后枚举支点位置,求$[1,x]$中以当前为支点的满足条件的个数

代码

#include <bits/stdc++.h>

#define Space putchar(' ')
#define Enter puts("")
#define MAXN 100010
#define int long long

using namespace std;

typedef long long ll;
typedef double Db;

inline ll Read()
{
    ll Ans = 0;
    char Ch = getchar() , Las = ' ';
    while(!isdigit(Ch))
    {
        Las = Ch;
        Ch = getchar();
    }
    while(isdigit(Ch))
    {
        Ans = (Ans << 3) + (Ans << 1) + Ch - '0';
        Ch = getchar();
    }
    if(Las == '-')
        Ans = -Ans;
    return Ans;
}

inline void Write(ll x)
{
    if(x < 0)
    {
        x = -x;
        putchar('-');
    }
    if(x >= 10)
        Write(x / 10);
    putchar(x % 10 + '0');
}

int Left , Right;
int Dp[20][20][3000] , Number[MAXN];

int DFS(int Position , int x , bool Flag , bool Limit , int Num)
{
    if(!Position)
        return Num == 0;
    if(!Limit && Dp[Position][x][Num] != -1)
        return Dp[Position][x][Num];
    int MAX = Limit ? Number[Position] : 9 , Ans = 0;
    for(int i = 0; i <= MAX; i++)
    {
        if(Flag)
            Ans += DFS(Position - 1 , x , Flag && i == 0 , 
                       Limit && i == MAX , i * (Position - x));
        else
            Ans += DFS(Position - 1 , x , Flag && i == 0 , 
                       Limit && i == MAX , Num + i * (Position - x));
    }
    if(!Limit)
        Dp[Position][x][Num] = Ans;
    return Ans;
}

inline int Solution(int x)
{
    int Count = 0 , Ans = 0;
    while(x)
    {
        Number[++Count] = x % 10;
        x /= 10;
    }
    for(int i = 1; i <= Count; i++)
        Ans += DFS(Count , i , 1 , 1 , 0);
    return Ans - Count + 1;
}

signed main()
{
    Left = Read() , Right = Read();
    memset(Dp , -1 , sizeof(Dp));
    if(!Left)
        Write(Solution(Right));
    else
        Write(Solution(Right) - Solution(Left - 1));
    return 0;
}

 

posted @ 2021-06-01 20:22  Tenderfoot  阅读(68)  评论(0编辑  收藏  举报