HDU 3709 Balanced Number 数位dp

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3709

Balanced Number

Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65535/65535 K (Java/Others)
#### 问题描述 > A balanced number is a non-negative integer that can be balanced if a pivot is placed at some digit. More specifically, imagine each digit as a box with weight indicated by the digit. When a pivot is placed at some digit of the number, the distance from a digit to the pivot is the offset between it and the pivot. Then the torques of left part and right part can be calculated. It is balanced if they are the same. A balanced number must be balanced with the pivot at some of its digits. For example, 4139 is a balanced number with pivot fixed at 3. The torqueses are 4*2 + 1*1 = 9 and 9*1 = 9, for left part and right part, respectively. It's your job > to calculate the number of balanced numbers in a given range [x, y]. #### 输入 > The input contains multiple test cases. The first line is the total number of cases T (0 < T ≤ 30). For each case, there are two integers separated by a space in a line, x and y. (0 ≤ x ≤ y ≤ 1018). #### 输出 > For each case, print the number of balanced numbers in the range [x, y] in a line. ####样例输入 > 2 > 0 9 > 7604 24324

样例输出

10
897

题意

求区间[L,R]内的一类平衡数,平衡数定义:存在一个数位,它两侧的力矩想等。 比如4139,存在数位3,有4*2+1*1=9*1

题解

数位dp,这题如果状态想对的话非常好写。
dp[i][j][sum]表示支点为j,前i位力矩和为sum的情况数。

特性:对于大于0的平衡数,支点有且只有一个,且如果考虑相对于支点的位差为每一位位权,所有位权和为0,如:4139有sum=4*2+1*1+3*0+9*(-1)=0

代码

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
#define scf scanf
#define prf printf

typedef __int64 LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;

const int INF=0x3f3f3f3f;
const LL INFL=0x3f3f3f3f3f3f3f3fLL;
const double eps=1e-8;
const double PI = acos(-1.0);

//start----------------------------------------------------------------------

const int maxn=22;

int arr[maxn],tot;

LL dp[maxn][maxn][1805];
///ismax标记表示前驱是否是边界值
LL dfs(int len,int j, int sum,bool ismax) {
    if(sum<0) return 0;
    if (len == 0) {
        if(sum==0) return 1;
        else return 0;
    }
    if (!ismax&&dp[len][j][sum]>=0) return dp[len][j][sum];
    LL res = 0;
    int ed = ismax ? arr[len] : 9;

    ///这里插入递推公式
    for (int i = 0; i <= ed; i++) {
        res += dfs(len - 1, j, sum+(len-j)*i,ismax&&i == ed);
    }
    return ismax ? res : dp[len][j][sum] = res;
}

LL solve(LL x) {
    tot = 0;
    while (x) { arr[++tot] = x % 10; x /= 10; }

    LL ret=0;
    for(int j=1;j<=tot;j++){
        ret+=dfs(tot,j,0,true)-1;
    }

    return ret+1;
}

int main() {
    clr(dp,-1);
    int tc;
    scf("%d",&tc);
    while(tc--){
        LL x,y;
        scf("%I64d%I64d",&x,&y);
        LL ans;
        if(x>0) ans=solve(y)-solve(x-1);
        else ans=solve(y);
        prf("%I64d\n",ans);
    }
    return 0;
}

//end-----------------------------------------------------------------------

Notes

这题关键的支点的性质想到了,但是状态少想了一个,发现很难转移,对于dp这种东西,如果时间,空间允许,状态越高维,问题应该会相对越好转移。

要发现引起你状态无法转移的变量,然后把它作为定值去枚举它!!!!!!!!!!!!!!!!!!

posted @ 2016-09-20 14:12  fenicnn  阅读(125)  评论(0编辑  收藏  举报