1 条题解
-
0
自动搬运
来自洛谷,原作者为

SNiFe
但行好事,莫问前程搬运于
2025-08-24 21:30:49,当前版本为作者最后更新于2017-10-25 17:49:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
#此题是数位DP,没学过数位DP的,这可以是一道很经典的入门题目
1. 本题是一道数位DP,首先我们可以只考虑设计算法求[1,x]这个区间内符合条件的数的个数即可。因为[x,y]这个区间内的个数实际上是[1,y]区间内的个数减去[1,x-1]区间内的个数。(注意要把0特殊出来考虑)
**2.**之后我们可以枚举支点的位置,对于每个满足条件的数,它所对应的支点是唯一的,原因是如果将支点右移,左边减去右边的差将严格单调增加。state表示力矩和(支点左边加支点右边),所以当state<0时,当前这个数不满足以i为支点成为杠杆数的情况,返回0。但当state==0时并不能就ans++了,因为当前枚举的位置可能还没枚举完。
**3.**枚举好支点,问题就转化为:求[1,x]中,以第i位为支点的杠杆数的个数。
==》 我们就可以用数位DP解决此问题。
注意:注意当力矩为负时,就要返回,否则会出现下标为负。
(数位DP可以从后往前推,也可以用记忆化搜索。我比较喜欢记忆化搜索,比较有套路。)
#代码附上:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int N=20; int a[N];//储存每一位的大小 LL dp[N][N][2500],l,r;//dp[i][j][k]表示考虑i位数字,支点为j,力矩和为k LL dfs(int pos,int point,int state,bool limit)//pos是几位数字;ponit是支点;state是力矩;limit表示当前这一位有无大小限制,防止枚举超过上限 { if(pos==0)return state==0;//判断是否合法 if(state<0)return 0;//当前力矩为负 if(!limit&&dp[pos][point][state]!=-1)return dp[pos][point][state]; int up=limit?a[pos]:9;//数位上限 LL tmp=0; for(int i=0;i<=up;i++)tmp+=dfs(pos-1,point,state+i*(pos-point),limit&&(i==up)); if(!limit)dp[pos][point][state]=tmp; return tmp; } LL solve(LL x) { int len=0; while(x) { a[++len]=x%10; x/=10; } LL ans=0; for(int i=1;i<=len;i++)ans+=dfs(len,i,0,1); return ans-len+1;//每次dfs都会重复搜索到00000……的情况这里减去重复数 } int main() { scanf("%lld %lld",&l,&r); memset(dp,-1,sizeof(dp)); printf("%lld",solve(r)-solve(l-1)); return 0; }
- 1
信息
- ID
- 801
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者