按位dp Balanced Number
题意:首先给出Balanced Number 的定义, Balanced Number是指一个数中选择一个位为支点, 然后按照天平的计算方法,如果左边和右边相等, 那么这个数就是一个Balanced Number,(例如4139 is a balanced number with pivot fixed at 3. The torqueses are 4*2 + 1*1 = 9 and 9*1 = 9),否则就不是。现在给出了一个区间让求出这个区间中的Balanced Number的个数。区间的范围为10^18.
思路: 这道题一开始的时候就像到了用数位dp。
开始想的是dp[now][sum][p][have] ,表示当前的状态为now, 前方的值为sum,当前在第p位, have表示是否已经经历了支点。 这样的话数组开不够。 现在发现其实可以少一维,将u那一维少了也不影响。
后来我的dp方程是这样开的,dp[now][p][w],表示当前的状态为now, 当前站在p点,支点为w。now可能为负值,因此可以加上一个常数N。 这样的话就可以往下边dp了,只不过求的时候要枚举起点。对了值得一说的是这里有一个剪枝,当now <0 && p < w时就可以直接return 0了。
后来交的时候wa了一次, 主要是我把0没有算成Balanced Number。
下面是代码:
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <string> using namespace std; typedef long long LL; const int N = 1610; LL dp[2*N][19][19], a, b; int num[20], pos; LL dfs(int now, int p, int w, bool istop) { if(p == -1) { if(now == 0) return 1; return 0; } if(now < 0 && p < w) return 0; if(!istop && dp[now+N][p][w] != -1) { return dp[now+N][p][w]; } int top = istop ? num[p]:9; LL ans = 0; for(int i=0; i<=top; i++) { if(p > w) { ans += dfs(now+(p-w)*i,p-1,w,istop&&i==top); } if(p == w) { ans += dfs(now, p-1, w, istop&&i==top); } if(p < w) { ans += dfs(now-(w-p)*i, p-1,w,istop&&i==top); } } if(!istop && dp[now+N][p][w] == -1) { dp[now+N][p][w] = ans; } return ans; } LL get(LL n) { if(n < 0) return 0; LL ans = 0; pos = 0; while(n) { num[pos++] = n%10; n /= 10; } for(int i=0; i<=pos-1; i++) { ans += dfs(0,pos-1,i,1); } ans -= pos-1; return ans; } int main() { int t; LL ans; memset(dp, -1, sizeof(dp)); scanf("%d", &t); while(t--) { scanf("%lld%lld", &a, &b); if(a > b) swap(a, b); ans = get(b) - get(a-1); printf("%lld\n", ans); } return 0; }


浙公网安备 33010602011771号