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; }