SPOJ BALNUM Balanced Numbers(数位dp,状态压缩)
BALNUM - Balanced Numbers
Balanced numbers have been used by mathematicians for centuries. A positive integer is considered a balanced number if:
1) Every even digit appears an odd number of times in its decimal representation
2) Every odd digit appears an even number of times in its decimal representation
For example, 77, 211, 6222 and 112334445555677 are balanced numbers while 351, 21, and 662 are not.
Given an interval [A, B], your task is to find the amount of balanced numbers in [A, B] where both A and B are included.
Input
The first line contains an integer T representing the number of test cases.
A test case consists of two numbers A and B separated by a single space representing the interval. You may assume that 1 <= A <= B <= 1019
Output
For each test case, you need to write a number in a single line: the amount of balanced numbers in the corresponding interval
Example
Input: 2 1 1000 1 9
Output: 147 4
题意是给出一个范围,求出这个范围中的平衡数的数量,平衡数是指这个数各个位置中的每种偶数都出现了奇数次,每种奇数都出现了偶数次。(也都可以不出现)
做法是用两个数t1, t2保存两种状态,t1保存(0~9)中的各个数字是否出现过,t2保存(0~9)中的各个偶数是否出现了奇数次,奇数是否出现了偶数次(先预处理)。这样子的话用(t1 & t2 == 0) 可以判断总的状态是否符合条件。显然t1、t2等于2 ^ 10 = 1024。
并且注意这道题里翻转过来的数字的第一位是0的话也会影响答案,所以如果高位为0时向下传递初始的状态。我用zip表示了压缩的初始的状态,毕竟zip是压缩包嘛_(:з」∠)_,然后就是简单的搞数位dp了。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <bitset> using namespace std; #define ll long long ll n, m; ll dp[20][1024][1024]; int dig[20]; int zip; void init() { for(int i = 0; i < 10; i += 2) zip ^= (1 << i); memset(dp, -1, sizeof(dp)); /*bitset<10> btt(zip); cout << btt << endl;*/ } void print(int num) { bitset<10> btt(num); cout << btt << endl; } ll dfs(int pos, int t1, int t2, int flag0, int lim) { //print(t1); print(t2); puts(""); if(pos == -1) return (t1 & t2) == 0; if(!lim && dp[pos][t1][t2] != -1) return dp[pos][t1][t2]; int End = lim ? dig[pos] : 9; ll ret = 0; for(int i = 0; i <= End; i++) { if(i == 0 && flag0) ret += dfs(pos - 1, 0, zip, 1, (i == End) && lim); else ret += dfs(pos - 1, t1 | (1 << i), t2 ^ (1 << i), 0, (i == End) && lim); } if(!lim) dp[pos][t1][t2] = ret; return ret; } ll func(ll num) { int n = 0; while(num) { dig[n++] = num % 10; num /= 10; } return dfs(n - 1, 0, zip, 1, 1); } int main() { init(); int t; scanf("%d", &t); while(t--) { scanf("%I64d %I64d", &n, &m); printf("%I64d\n", func(m) - func(n - 1)); } }