数位DP也就这样子了,看了别人的思路,写下来的代码居然就一模一样了,可见数位DP的框架还真就定死了的。
用dp[pos][o][pre] 表示状态,然后枚举中间点就知道怎么做了。
反正框架就是这个样子了,一位一位的往后推,记录前面数字的状态就可以了,变化无非就是前面数字的状态表示,想到了状态如何表示,题目就迎刃而解了。
数位DP的考点应该就是状态的建模了。
#include<iostream>
#include<cstring>
#include<cstdio>
#define fuck(a) printf("%s\n", a);
using namespace std;
typedef long long LL;
const int MAXN =20;
LL dp[MAXN][MAXN][MAXN*100];
//dp[i][j][k] i表示当前位置,j表示支点位置,k表示位置i前面已经得到的力矩和
template<typename T>
T oabs(T a){return a<0?-a:a;}
int num[MAXN],len;
LL dfs(int pos,int o,int pre,bool limit)
{
if(pos<1)
{
return pre==0;
}
if(!limit&&~dp[pos][o][pre])return dp[pos][o][pre];
LL res =0 ;
int end = limit ?num[pos]:9;
for(int i=0;i<=end;i++)
{
res += dfs(pos-1,o,pre+(pos-o)*i,limit&&(i==end));
}
if(!limit)dp[pos][o][pre]=res;
return res;
}
LL solve(LL n)
{
//cout<<"this is n "<<n;
if(n==-1||n==0)return n+1;
len =1;
LL temp = n;
while(n)
{
num[len++]=n%10;
n/=10;
}
len--;
LL res =0;
for(int i=1;i<=len;i++)
{
res+=dfs(len,i,0,true);
}
return res-len+1;
}
int main()
{
freopen("data.in","r",stdin);
LL a,b;
int T;
memset(dp,-1,sizeof(dp));
scanf("%d",&T);
while(T--)
{
scanf("%I64d%I64d",&a,&b);
LL r1=solve(b);
LL r2=solve(a-1);
printf("%I64d\n",r1-r2);
}
return 0;
}