【BZOJ1183】[Croatian2008]Umnozak【数位DP】【质因数分解】【枚举】【记忆化搜索】

【题目链接】

参考官方题解写的

【官方题解下载地址】

/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

int cnt[5];
LL A, B, lb, ub, ans, dp[20][33][20][14][12], dec[20];

int fact[] = {2, 3, 5, 7};
int code[11][4] = {
	{0, 0, 0, 0},
	{0, 0, 0, 0},
	{1, 0, 0, 0},
	{0, 1, 0, 0},
	{2, 0, 0, 0},
	{0, 0, 1, 0},
	{1, 1, 0, 0},
	{0, 0, 0, 1},
	{3, 0, 0, 0},
	{0, 2, 0, 0}
};

inline LL ceil(LL a, LL b) {
	return (a + b - 1) / b;
}

inline LL floor(LL a, LL b) {
	return a / b;
}

inline LL dfs(int x, LL pref) {
	LL b = pref + dec[x] - 1;
	if(pref > ub || b < lb) return 0;
	if(x == 0) return !cnt[0] && !cnt[1] && !cnt[2] && !cnt[3];

	bool memo = 0;
	if(pref >= lb && b <= ub) memo = 1;
	if(memo && ~dp[x][cnt[0]][cnt[1]][cnt[2]][cnt[3]]) return dp[x][cnt[0]][cnt[1]][cnt[2]][cnt[3]];

	LL res = 0; x--;
	for(int i = (pref != 0); i <= 9; i++) {
		bool flag = 1;
		for(int k = 0; k < 4; k++) flag &= code[i][k] <= cnt[k];
		if(!flag) continue;

		for(int k = 0; k < 4; k++) cnt[k] -= code[i][k];
		res += dfs(x, pref + dec[x] * i);
		for(int k = 0; k < 4; k++) cnt[k] += code[i][k];
	}

	if(memo) dp[x + 1][cnt[0]][cnt[1]][cnt[2]][cnt[3]] = res;
	return res;
}

inline void solve(int x, LL prod) {
	if(prod > 1000000000 || prod * prod > B) return;
	if(x == 4) {
		lb = ceil(A, prod); ub = floor(B, prod);
		ans += dfs(18, 0);
		return;
	}

	solve(x + 1, prod);
	cnt[x]++;
	solve(x, prod * fact[x]);
	cnt[x]--;
}

int main() {
	dec[0] = 1;
	for(int i = 1; i < 19; i++) dec[i] = (dec[i - 1] << 3) + (dec[i - 1] << 1);
	memset(dp, -1, sizeof(dp));

	scanf("%lld%lld", &A, &B);

	solve(0, 1);

	printf("%lld\n", ans);
	return 0;
}


你可能感兴趣的:(【BZOJ1183】[Croatian2008]Umnozak【数位DP】【质因数分解】【枚举】【记忆化搜索】)