【SPOJ-BALNUM】Balanced Numbers【数位DP】【状态压缩】

【题目链接】

题意:问[L, R]内有多少数字,满足每个奇数都出现了偶数次,每个偶数都出现了奇数次(没有出现的数不考虑)

用三进制来表示状态,0表示没出现,1表示出现奇数次,2表示出现偶数次。

然后就是裸的数位DP了。

/* Telekinetic Forest Guard */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef unsigned long long ULL;

const int maxn = 20, maxm = 59055;

int dig[maxn], ter[maxn];
ULL dp[maxn][maxm];

template <class numtype>
inline void read(numtype &x) {
	int f = 0; x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? 1 : 0;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	if(f) x = -x;
}

inline bool check(int s) {
	for(int i = 0; i <= 9 && s; i++, s /= 3) {
		int k = s % 3;
		if(!k) continue;
		if((i & 1) && (k & 1)) return 0;
		if((~i & 1) && (~k & 1)) return 0;
	}
	return 1;
}

inline int newst(int s, int x) {
	int k = (s / ter[x]) % 3;
	s -= k * ter[x];
	if(!k) k = 1;
	else k = 3 - k;
	return s += k * ter[x];
}

inline ULL dfs(int pos, int state, bool limit, bool zero) {
	if(pos == 0) return check(state);
	if(!limit && !zero && ~dp[pos][state]) return dp[pos][state];

	int upb = limit ? dig[pos] : 9;
	ULL res = 0;
	for(int i = 0; i <= upb; i++)
		res += dfs(pos - 1, (zero && !i) ? 0 : newst(state, i), limit && i == dig[pos], zero && !i);

	if(!limit && !zero) dp[pos][state] = res;
	return res;
}		

inline ULL calc(ULL x) {
	int top = 0;
	for(; x; x /= 10) dig[++top] = x % 10;
	return dfs(top, 0, 1, 1);
}

int main() {
	int T; ULL l, r;
	memset(dp, -1, sizeof(dp));
	ter[0] = 1;
	for(int i = 1; i <= 9; i++) ter[i] = (ter[i - 1] << 1) + ter[i - 1];

	for(read(T); T; T--) {
		read(l); read(r);
		printf("%llu\n", calc(r) - calc(l - 1));
	}
	return 0;
}


你可能感兴趣的:(【SPOJ-BALNUM】Balanced Numbers【数位DP】【状态压缩】)