题目:
HDU3709
题意:
定义以一个数的某一位为中心点,每一位的价值为这一位上的数*距离中心点的距离,若中心点两边的价值之和相同,则此数平和(即将一个数看做一个天平,是否平衡)。求给定区间[l, r]中的平衡的数的个数。
方法:
数位DP
定义状态:dfs(intpos, int mid, int dif, bool flag),pos为当前的位置,mid表示中心点位置,dif表示左右两边的差值,flag表示当前是否受限。
状态转移:cDif =(pos > mid)? (dif + i * (pos - mid)) : (dif - i * (mid - pos));
由于数位DP其实也是在枚举所有1~n的数,且它们的位数是相同的(不足的用前缀0补齐),所有0的表示其实是000…0,所以此数会产生多种平衡情况导致重复计数,所以返回值需要减去(长度-1)。
测试数据:
2
0 9
0 10
答案:
10
11
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<climits>
#include<cstdlib>
using namespace std;
//#define DEBUG
typedef long long ll;
int num[20];
ll f[20][20][2000];
ll dfs(int pos, int mid, int dif, bool flag)
{
if ( !pos ) return (dif == 0);
if ( !flag && ~f[pos][mid][dif] ) return f[pos][mid][dif];
int sig = (flag)? num[pos]:9;
ll ans = 0;
for (int i = 0; i <= sig; i++){
int cDif = (pos > mid)? (dif + i * (pos - mid)) : (dif - i * (mid - pos));
ans += dfs(pos - 1, mid, cDif, flag && (i == sig));
}
if ( !flag ) f[pos][mid][dif] = ans;
#ifdef DEBUG
cout<<"pos="<<pos<<" mid="<<mid<<" dif="<<dif<<" flag="<<flag<<" f="<<ans<<endl;
#endif
return ans;
}
ll getAns(ll x)
{
#ifdef DEBUG
cout<<"num="<<x<<endl;
#endif
if ( x < 0 ) return 0;
if ( x == 0 ) return 1;
int sig = 0;
while ( x ) num[++sig] = x % 10, x /= 10;
ll ans = 0;
for (int i = 1; i <= sig; i++) ans += dfs(sig, i, 0, 1);
#ifdef DEBUG
cout<<"ans="<<ans<<endl;
#endif
return ans - (sig - 1);
}
int main()
{
//freopen("in.txt", "r", stdin);
memset(f, -1, sizeof(f));
//for (int i = 0; i <= 200; i++) if ( getAns(i) - getAns(i-1) == 1 ) cout<<i<<" ";
int T;
scanf("%d", &T);
while ( T-- )
{
ll l, r;
scanf("%I64d%I64d", &l, &r);
printf("%I64d\n", getAns(r) - getAns(l - 1));
}
return 0;
}