码迷,mamicode.com
首页 > 其他好文 > 详细

题解:杠杆数

时间:2021-06-02 20:33:08      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:输出   等于   概念   输入   前缀和   暴力枚举   include   条件   数组   

题目

题目描述

如果把一个数的某一位当成支点,且左边的数字到这个点的力矩和等于右边的数字到这个点的力矩和,那么这个数就可以被叫成杠杆数。
比如4139就是杠杆数,把3当成支点,我们有这样的等式:4 * 2 + 1 * 1 = 9 * 1。
给定区间[x,y],求出在[x,y]中有几个杠杆数。

输入格式

两个数,表示x,y。

输出格式

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

输入输出样例

输入
7604 24324
输出
897

解析

这道题属于数位DP。
什么是数位DP呢?
数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位......数的每一位就是数位啦!
之所以要引入数位的概念完全就是为了dp。数位dp的实质就是换一种暴力枚举的方式,使得新的枚举方式满足dp的性质,然后记忆化就可以了。
那么我们定义一个dp数组:dp[pos][pl][num1]表示位数为pos,杠杆支点位置在pl,力矩和为num1的数字的个数。
然后在处理结果方面我们可以使用一个前缀和的思想:solve(x)求的是不大于x的满足条件的数的个数,那么区间[l,r]的答案就是solve(r) - solve(l - 1) 了。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T;
int dp[20][20][2005],num[205],l,r;
int dfs(int pos,int x,bool flag,bool lim,int num1) {
    if(!pos) return num1 == 0;
    if(!lim && dp[pos][x][num1] != -1) return dp[pos][x][num1];
    int maxx = lim ? num[pos] : 9,ans = 0;
    for(int i = 0; i <= maxx; i++) {
	    if(flag) ans += dfs(pos - 1,x,flag && i == 0,lim && i == maxx,i * (pos - x));
	    else ans += dfs(pos - 1,x,flag && i == 0,lim && i == maxx,num1 + i * (pos - x));
    }
    if(!lim) dp[pos][x][num1] = ans;
    return ans;
}
int solve(int x) {
    int ans = 0,cnt = 0;
    while(x) num[++cnt] = x % 10,x /= 10;
    for(int i = 1; i <= cnt; i++) ans += dfs(cnt,i,1,1,0);
    return  ans - cnt + 1;
}
signed main() {
    memset(dp,-1,sizeof(dp));
    scanf("%lld %lld" ,&l,&r);
    if (!l) printf("%lld\n" ,solve(r));
    else printf("%lld\n" ,solve(r) - solve(l - 1));
    return 0;
}

题解:杠杆数

标签:输出   等于   概念   输入   前缀和   暴力枚举   include   条件   数组   

原文地址:https://www.cnblogs.com/Crazyman-W/p/14838738.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!