题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709
题目来源:2010成都区域赛,之前存在手里的题目。
简要题意:定义平衡数,选取一位为平衡点,其向两边距离和位的乘积的加和相等。
4139 选取 3 为平衡点则4×2+1×1=9=9×1 ,是平衡数。
求 [l,r] 间平衡数的个数。数据范围: 0<T⩽30;0⩽l,r⩽1018
题解
看到题目可以想到应该是道数位dp,开始的时候,一直在考虑将和保存到下标里,可是这样递推就不知道每位的和了,再加一位,然后因为最后发现变得极其复杂,因为还需要考虑平衡点是空出来的。
最后发现网上的做法极其简洁,不是考虑让两边的和相等,而是前面减后面的等于 0 。
更进一步地,发现如下规律:
令
x=akak−1⋯a1(ak>0) 为十进制的展开。
令piv为平衡点,定义f(x,piv)=∑i=1k(i−piv)×ai可以发现 f(x,piv)=0 是选取 piv 为平衡点时 x 为平衡数的充要条件。从中我们也可以发现:
即除非每位都是 0 ,固定了f(x,piv+1)=f(x,piv)+∑i=1kai(piv<k) x 后这个函数随着 piv 严格单调变化的。那么对于一个 x 只有一个
piv 可以让它成为平衡数。我们可以记录对于一个长度 piv 在哪个, f(x,piv) 为多少的有多少个。
然后去找每个长度 f(x,piv)=0 的个数,减去 0 中重复的情况得到答案。
实现
经过思路上的化简之后,题目变得相当简洁,注意要减去
0 重复的情况还有当前和小于 0 <script type="math/tex" id="MathJax-Element-25">0</script>可以直接退出。
代码
#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 second
using 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;}
// head
LL 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;
}