您的位置:首页 > 理论基础 > 计算机网络

hdu 5898 - odd-even number (2016沈阳网络赛) - 数位dp

2016-09-21 15:29 579 查看
题意:如果一个数字连续的奇数都为偶数个,连续的偶数个数都为奇数,那么这个数字就是奇偶数,输入l,r,问[l, r]闭区间有多少个奇偶数。

数位dp用dp[i][j][k]表示长度为i并且最高位为j的数字并且与最高位数字奇偶情况相同的连续位数为k的满足题目条件的数字有多少个,k=0表示偶数长度,k=1表示奇数长度。状态转移的条件会比较麻烦:

如果高位为奇数位偶数,可以向偶数位偶数和奇数位奇数转移(就是可以在最高位前面添加以为奇数或者以为偶数);

如果高位为偶数位偶数,那么只能在前面添加一位偶数,即只能向奇数位偶数转移;

如果高位有偶数位奇数,可以向奇数位奇数转移也可以向奇数位偶数转移;

如果高位为奇数位奇数,只能向偶数位奇数转移。

查询和一般的数位dp差不太多,要注意高位的数字对当前状态的影响。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll dp[20][10][2];
ll pw[20];
int judge(int l, int m, int j, int k) {
if(!l && !m && !j && k) return 1;
if(!l && m && !j && !k) return 1;
if((l ^ m) && j && k) return 1;
if(l && !m && !j && k) return 1;
if(l && m && j && !k) return 1;
return 0;
}
void init() {
dp[0][1][0] = 1;
int i, j, k, s, l, m;
for(i = 1; i < 20; i++) {
for(j = 0; j < 10; j++) {
for(k = 0; k < 2; k++) {
for(l = 0; l < 10; l++) {
for(m = 0; m < 2; m++) {
if(judge(l & 1, m, j & 1, k)) {
dp[i][j][k] += dp[i - 1][l][m];
}
}
}
}
}
}
pw[0] = 1;
for(i = 1; i < 19; i++) {
pw[i] = pw[i - 1] * 10;
}
}
ll add(ll u, int l, int o = 0, int n = 0, int f = 0) {
if(!u) return 0;
ll ans = 0;
ll t = pw[l - 1] * (u / pw[l - 1]);
for(int i = (f ? l : 1); i <= l; i++) {
for(int j = (f ? 0 : 1); j < 10 && j * pw[i - 1] < t; j++) {

if(!f || (o && !n)) ans += dp[i][j][(j & 1) ^ 1];
else if(o == 0 && n == 1) {
ans += dp[i][j][0];
}
else if(o && n && (j & 1)) {
ans += dp[i][j][1];
}
else if(!o && !n && (j & 1) == 0){
ans += dp[i][j][1];
}
}

}
int x = (u / pw[l - 1]) & 1;
if(x == o) ans += add(u % pw[l - 1], l - 1, x, n ^ 1,f + 1);
else if((o ^ n) || !f) ans += add(u % pw[l - 1], l - 1, x, 1,f + 1);
return ans;
}
int main() {
init();
ll d;
int t, ks = 1;
ll l, r;
scanf("%d", &t);
while(t--) {
scanf("%I64d%I64d", &l, &r);
int lt1 = 0, lt2;
r++;
for(lt1 = 18; pw[lt1] > l; lt1--);
for(lt2 = 18; pw[lt2] > r; lt2--);
printf("Case #%d: %I64d\n", ks++, add(r, lt2 + 1) - add(l, lt1 + 1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息