您的位置:首页 > 其它

hdu3709(数位dp)

2015-11-05 20:36 363 查看
求区间[l,r]内有多少个数的满足: 选一个位为中点,是的左边的数到该位的距离等于右边的位到该位的距离。

比如4139 选择3位中点, 那么左边的距离是 4 * 2 + 1 * 1 , 右边的距离是9 * 1

想了半天,想到了枚举哪一位作为中点, 然后进行数位dp, 但是样例错了, 忽然想到会重复啊,就百度了一下

原来只有0在枚举中点时会重复,其他的数有且只有一个中点是的左边的距离等于右边的距离

所以只要最后ans-len+1即可

#include <functional>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#pragma warning(disable:4996)
using namespace std;
typedef long long LL;
const int INF = 0x7fffffff;
const int mod = 2520;
LL dp[22][22][4000];
int num[22];

LL dfs(int cur, int mid, int diff, bool flag)
{
if (cur == 0) return diff == 2000;
if (!flag && dp[cur][mid][diff] != -1)
return dp[cur][mid][diff];
LL ret = 0;
int end = flag ? num[cur] : 9;
for (int i = 0; i <= end; ++i)
{
int newDiff = diff;
if (cur > mid)
newDiff += (cur - mid) * i;
else if (cur < mid)
newDiff -= (mid - cur) * i;
ret += dfs(cur - 1, mid, newDiff, i == end && flag);
}
if (!flag)
dp[cur][mid][diff] = ret;
return ret;
}
LL calc(LL n)
{
int len = 0;
while (n)
{
num[++len] = n % 10;
n /= 10;
}
LL ret = 0;

for (int i = 1; i <= len; ++i)
ret += dfs(len, i, 2000,true);
//0每次枚举中点时都被计算进去了,所以要剪掉
return ret - len + 1;

}
int main()
{
memset(dp, -1, sizeof(dp));
int t;
LL l, r;
scanf("%d", &t);
while (t--)
{
scanf("%I64d%I64d", &l, &r);
if (l == 0)
printf("%I64d\n", calc(r));
else
printf("%I64d\n", calc(r) - calc(l - 1));
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: