【SPOJ-GONE】G-One Numbers【数位DP】【记忆化搜索】【质数筛】

【题目链接】

题意:求[L, R]内有多少数字,数位之和为质数。

最大和不超过72,于是先筛出72内每个数是不是质数。当然也可以筛到100。

设dp[i][sum]表示到第i位,前i位和为sum时的数字个数。

直接枚举每位转移就行了。

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

using namespace std;

const int maxn = 20, maxm = 100;

int dig[maxn], prime[maxm], cnt, dp[maxn][maxm];
bool isnotprime[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 void getprime() {
	isnotprime[0] = 1;
	isnotprime[1] = 1;
	for(int i = 2; i < maxm; i++) {
		if(!isnotprime[i]) prime[++cnt] = i;
		for(int j = 1; j <= cnt && i * prime[j] < maxm; j++) {
			isnotprime[i * prime[j]] = 1;
			if(i % prime[j] == 0) break;
		}
	}
}

inline int dfs(int pos, int sum, bool limit) {
	if(pos == 0) return !isnotprime[sum];
	if(!limit && ~dp[pos][sum]) return dp[pos][sum];

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

	if(!limit) dp[pos][sum] = res;
	return res;
}

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

int main() {
	getprime();
	int T, l, r;
	memset(dp, -1, sizeof(dp));
	for(read(T); T; T--) {
		read(l); read(r);
		printf("%d\n", calc(r) - calc(l - 1));
	}
	return 0;
}


你可能感兴趣的:(【SPOJ-GONE】G-One Numbers【数位DP】【记忆化搜索】【质数筛】)