题目大意:
定义长度为
2n
的幸运数为前
n
位数之和等于后
分析:
恶心的数位
DP
,说它恶心并不是因为有多难写,而是因为之前我
×
掉了我无数的做法才做出来的。
设
f[i][j][k][p][q]
表示长度为
j
的当前在第
没有上界的限制情况下,我们可以枚举下一位,前
n
个数做加法,后
AC code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define half(x) ((x)>>1)
using namespace std;
const int NUM = 10;
const int SUM = 100;
int f[NUM][NUM][SUM][NUM][NUM];
int a[NUM], len;
int dp(int now, int n, int sum, int up, int down, bool flag)
{
if(!now) return sum != 50 && sum+up >= 50 && sum-down <= 50;
if(!flag && f[now][n][sum][up][down] >= 0) return f[now][n][sum][up][down];
int ret = 0;
int tot = flag?a[now]:9;
int i = now==n?1:0;
while(i <= tot)
{
int s, u, d;
s = now>half(n)?sum+i:sum-i;
u = now>half(n)?max(up,9-i):max(up,i);
d = now>half(n)?max(down,now==n?i-1:i):max(down,9-i);
ret += dp(now-1, n, s, u, d, flag&&i==tot);
++i;
}
if(!flag) f[now][n][sum][up][down] = ret;
return ret;
}
int solve(int n)
{
if(n == -1 || !n) return 0;
len = 0;
while(n)
{
a[++len] = n%10;
n /= 10;
}
int ret = 0;
for(int i = 2; i <= len; i += 2)
ret += dp(i, i, 50, 0, 0, i==len);
return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
memset(f, -1, sizeof f);
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", solve(b)-solve(a-1));
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}