HDU ~ 3709 ~ Balanced Number (数位dp)

题意

求[L,R]区间内Balanced Number有多少个,Balanced Number定义为:可以以某个数作为支点,左右两边力矩和相等的数字。

比如:4139,我们选3作为支点,4和支点距离为2,1和3距离为1,9和3距离为1。4*2+1*1=9*1,那么4139为平衡数。

思路

首先对于一个数,不可能有两个支点。同样数位DP的做法,我们枚举一下这个支点位置就好了。

dp[pos][Pivot][sum]表示选到pos位置,支点为Pivot,力矩和为sum的情况。

我们把支点左边的记为力矩和记为+,右边记为-,如果sum<0以后表示到了右半部分,sum不会再增加了,此时我们返回0就好

0这个数字,每个支点都会算一次,减一下就好了。

注意下左端点为0这个情况。。。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long LL;
LL L, R, dp[20][20][2000];
string num;
LL dfs(int pos, int Pivot, int sum, bool limit)
{
    if (pos == -1) return sum == 0;
    if (sum < 0) return 0;
    if (!limit && dp[pos][Pivot][sum] != -1) return dp[pos][Pivot][sum];
    LL ans = 0;
    int E = limit?num[pos]-'0':9;
    for (int i = 0; i <= E; i++)
        ans += dfs(pos-1, Pivot, sum+(pos-Pivot)*i, limit&&(i==E));
    if (!limit) dp[pos][Pivot][sum] = ans;
    return ans;
}
LL solve(LL x)
{
    if (x < 0) return 0;
    num = to_string(x); reverse(num.begin(), num.end());
    LL ans = 0;
    for (int i = 0; i < num.size(); i++)//枚举Pivot
        ans += dfs(num.size()-1, i, 0, 1);
    return ans - (num.size()-1);
}
int main()
{
    memset(dp, -1, sizeof(dp));
    int T; scanf("%d", &T);
    while (T--)
    {
        scanf("%lld%lld", &L, &R);
        printf("%lld\n", solve(R)-solve(L-1));
    }
    return 0;
}
/*
2
0 9
7604 24324
*/

猜你喜欢

转载自blog.csdn.net/zscdst/article/details/81085190