hdu 3709 Balanced Number 2010成都区域赛 数位dp

来源:互联网 发布:有关大数据的例子 编辑:程序博客网 时间:2024/04/30 15:09

题目

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

题目来源:2010成都区域赛,之前存在手里的题目。

简要题意:定义平衡数,选取一位为平衡点,其向两边距离和位的乘积的加和相等。
    4139选取3为平衡点则4×2+1×1=9=9×1,是平衡数。
    [l,r]间平衡数的个数。

数据范围:0<T30;0l,r1018

题解

看到题目可以想到应该是道数位dp,开始的时候,一直在考虑将和保存到下标里,可是这样递推就不知道每位的和了,再加一位,然后因为最后发现变得极其复杂,因为还需要考虑平衡点是空出来的。

最后发现网上的做法极其简洁,不是考虑让两边的和相等,而是前面减后面的等于0

更进一步地,发现如下规律:

x=akak1a1(ak>0)为十进制的展开。

pivf(x,piv)=i=1k(ipiv)×ai
可以发现f(x,piv)=0是选取piv为平衡点时x为平衡数的充要条件。

从中我们也可以发现:

f(x,piv+1)=f(x,piv)+i=1kai(piv<k)
即除非每位都是0,固定了x后这个函数随着piv严格单调变化的。

那么对于一个x只有一个piv可以让它成为平衡数

我们可以记录对于一个长度piv在哪个,f(x,piv)为多少的有多少个。

然后去找每个长度f(x,piv)=0的个数,减去0中重复的情况得到答案。

实现

经过思路上的化简之后,题目变得相当简洁,注意要减去0重复的情况还有当前和小于0可以直接退出。

代码

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#include <queue>#include <string>#include <vector>#include <set>#include <map>#define pb push_back#define mp make_pair#define all(x) (x).begin(),(x).end()#define sz(x) ((int)(x).size())#define fi first#define se secondusing namespace std;typedef long long LL;typedef vector<int> VI;typedef pair<int,int> PII;LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}// headLL dp[25][25][2005];int num[25];LL dfs(int pos, int piv, bool e, int cursum) {    if (pos == 0) return cursum == 0;    if (cursum < 0) return 0;    if (!e && dp[pos][piv][cursum] != -1) return dp[pos][piv][cursum];    int lim = e ? num[pos] : 9;    LL ans = 0;    for (int i = 0; i <= lim; i++) {        ans += dfs(pos-1, piv, e&&i==lim, cursum+(pos-piv)*i);    }    if (!e) dp[pos][piv][cursum] = ans;    return ans;}LL solve(LL x) {    if (x <= 0) return x+1;    int len = 0;    while (x) {        num[++len] = x%10;        x /= 10;    }    LL ans = 0;    for (int i = len; i >= 1; i--) {        ans += dfs(len, i, true, 0);    }    return ans-len+1;}int main(){    memset(dp, -1, sizeof dp);    int t;    scanf("%d", &t);    while (t--) {        LL l, r;        scanf("%I64d%I64d", &l, &r);        printf("%I64d\n", solve(r)-solve(l-1));    }    return 0;}
0 0
原创粉丝点击