HDU3709 Balanced Number[数位DP]

题意:
给T组数据,每组数据给出一个x和y,求出[x,y]当中满足以其中一位为平衡点,满足在平衡点的左右两边的力矩大小一致。

题解:
这道题要注意前导零的问题,因为不记录前导零,如果左界也不是0,会多出len-1种情况(len是这个数共有多少位),那么如果左界是0,就需要记录一下。
因为有这种问题,所以我写的时候记录了前导零,然后如果出现边界有0的情况,左界出现的话,为了补上,而把ans预置为-1(因为计算过程是solve(y)-solve(x-1)所以当前数为-1的时候,代表边界为0,最小也只有为0,补上-1即在最终结果上面+1)。然后,要枚举出每一位作为平衡点的时候的情况,然后将所有情况的结果加起来,就是我们需要的结果了。

所以结果的本身是求符合这个式子,同时,因为力矩在计算过程中不可能存在负数,所以如果出现了负数,那么就直接可以返回0了,因为是不可能的情况。

状态转移的话,dp[i][j][k] 首先第一维记录当前位置,第二维记录平衡点是哪个位置,第三维记录所有sum的结果,而sum的最大值大概取9*9*18(即取最边上的界最大值的sum)。


#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=20;
const int M=1500;//9*9*18
ll dp[N][N][M];
int num[N];
ll dfs(int pos,int sum,int mid,bool first,bool limit)
{
    if (pos==-1)
        return first?(!sum):0;
    if (sum<0)
        return 0;
    if (!limit && first && dp[pos][mid][sum]!=-1)
        return dp[pos][mid][sum];
    int up=limit?num[pos]:9;
    ll cnt=0;
    for (int i=0 ; i<=up ; ++i)
    {
        if (!first)
        {
            if (i)
                cnt+=dfs(pos-1,sum+(pos-mid)*i,mid,1,limit && i==num[pos]);
            else
                cnt+=dfs(pos-1,sum+(pos-mid)*i,mid,first,limit && i==num[pos]);
        }
        else
            cnt+=dfs(pos-1,sum+(pos-mid)*i,mid,first,limit && i==num[pos]);
    }

    if (!limit && first)
        dp[pos][mid][sum]=cnt;
    return cnt;
}
ll solve(ll n)
{
    int pos=0;
    ll ans=n==-1?-1:0;//如果左界为0 补上一个平衡(因为dfs过程中不计算前导0,即漏算了0的情况)
    if (n==-1)
        n=0;
    while (n)
    {
        num[pos++]=n%10;
        n/=10;
    }
    for (int i=pos-1 ; i>=0 ; --i)
        ans+=dfs(pos-1,0,i,0,1);
    return ans;
}
int main()
{
    memset(dp,-1,sizeof(dp));
	int T;
	scanf("%d",&T);
	while (T--)
    {
        ll x,y;
        scanf("%lld%lld",&x,&y);
        printf("%lld\n",solve(y)-solve(x-1));
    }
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值