分析

看到题的第一反应,存储前面 n 位的值乘坐标,然后暴力检查,然而时间复杂度虽是可的,但没有正确性,我们发现对于同一个值,可能有多种可能性,比如第一位为三,第二位为一和第一位为三,第二位为二以此种方法计算出的值是相同的,但很明显他们对应的方案不一样。

因此我们需要考虑一种对于一个计算出的值,我们能百分之百保证它的 dp 中存的方案数是正确的,所以我们考虑确定支点的位置,可以发现在你确定了支点之后,无论你怎么弄前面的 n 位,后面的方案数一定是确定的,做个类比,你之前的不确定支点位置的情况下,左右移动端点会影响方案数,但在确定了支点后这种情况就避免掉了,所以对于一个数,我们枚举第一位到最后一位作为支点,在数位 dp 过程中,力矩加值为该位乘上支点下标减去该位置下标,小于零时排除掉,所以我们 pos 从一开始,这样就可以先为正值,后面变为负值时就可以放心排除了。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int dp[20][2500],tot,sw[25],a,b,qz[20],ss[20];

int dfs(int pos,int zd,int lim,int he){//位置,支点,上限,力矩和 
	if(pos==tot+1)return he==0;
	if(he<0)return 0;
	if(!lim&&dp[pos][he]!=-1)return dp[pos][he];
	int sum=0,mx=lim?sw[tot-pos+1]:9;
	for(int i=0;i<=mx;i++){
		sum+=dfs(pos+1,zd,lim&&(i==mx),he+i*(zd-pos));
	}
	if(!lim)return dp[pos][he]=sum;
	return sum;
}

int search(int x){
	if(x==0)return 1;
	tot=0;
	while(x){
		sw[++tot]=x%10;
		x/=10;
	}
	memset(dp,-1,sizeof(dp));
	int sum=0;
	for(int i=1;i<=tot;i++){//枚举支点 
		memset(dp,-1,sizeof(dp));
		sum+=dfs(1,i,1,0);
	}
	return sum-tot+1;
}

signed main()
{
	cin>>a>>b;
	cout<<search(b)-search(a-1);//前缀思想 
	return 0;
}