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

来源:互联网 发布:剑三脸型数据怎么用 编辑:程序博客网 时间:2024/05/16 00:50

题意:如果一个数字连续的奇数都为偶数个,连续的偶数个数都为奇数,那么这个数字就是奇偶数,输入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;}


0 0