您的位置:首页 > 运维架构

【SPOJ-KOPC12H】K12-OE Numbers【数位DP】

2016-02-25 10:48 363 查看
题意:

定义OE数为:对于所有数位,使得偶数和大于奇数和的数。

比如1233,奇数和 = 1 + 3 + 3 = 7,偶数和 = 2,奇数和 > 偶数和,不是OE数。

设f[i][k]表示长度为i的数,偶数和减奇数和等于k的OE数的个数。

对于当前位j,

如果j为奇数,那么f[i][k] += f[i - 1][k + j]

如果j为偶数,那么f[i][k] += f[i - 1][k - j]

求个前缀和f[i][j] += f[i][j + 1],变为 f[i][k]表示长度为i的数,偶数和减奇数和大于等于k的OE数的个数。

计算的时候定义一个sum,表示已经计算过的位数的偶数和减奇数和。

统计答案时我们只需要让偶数和减奇数和大于0(大于等于1)就好,即对于当前位j,

如果j为奇数,ans += f[i - 1][-sum + j + 1]

如果j为偶数,ans += f[i - 1][-sum - j + 1]

注意边界情况,还有负下标的处理。

#include <cstdio>

const int maxn = 15;

int *f[maxn], A[maxn], tmp[maxn][200];

inline int get(int x, int y) {
if(x) return f[x][y];
return y <= 0;
}

inline int calc(int x) {
if(x == 100000000) x--;
if(x == 0) return 0;

int cnt = 0;
for(; x; x /= 10) A[++cnt] = x % 10;

int ans = 0, sum = 0;
for(int i = cnt; i >= 1; i--) {
for(int j = 0; j < A[i]; j++)
if(j & 1) ans += get(i - 1, -sum + j + 1);
else ans += get(i - 1, -sum - j + 1);
if(A[i] & 1) sum -= A[i];
else sum += A[i];
}

if(sum > 0) ans++;
return ans;
}

int main() {
for(int i = 0; i < 10; i++) f[i] = &tmp[i][100]; f[0][0] = 1;

for(int i = 1; i <= 8; i++) for(int j = 0; j < 10; j++) for(int k = -72; k <= 72; k++)
if(j & 1) f[i][k] += f[i - 1][k + j];
else f[i][k] += f[i - 1][k - j];

for(int i = 0; i <= 8; i++) for(int j = 71; j >= -72; j--) f[i][j] += f[i][j + 1];

int T; scanf("%d", &T);
while(T--) {
int a, b; scanf("%d%d", &a, &b);
printf("%d\n", calc(b) - calc(a - 1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数位DP