数位DP题集

来源:互联网 发布:天津大学软件学院位置 编辑:程序博客网 时间:2024/06/05 20:56

强烈推荐记忆化搜索写法,好写,通用。

入门题:

hdoj 2089


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);int table[10][2];int digit[10];int dfs(int len, int flag, bool bound){    if(len == 0)        return 1;    if(!bound && table[len][flag] != -1)        return table[len][flag];    int up = bound? digit[len]: 9;    int ret = 0;    for(int i = 0; i <= up; ++i)    {        if(i == 4 || (flag && i == 2))            continue;        ret += dfs(len-1, (i == 6? 1: 0), bound && i == up);    }    if(!bound)        table[len][flag] = ret;    return ret;}int fun(int num){    int len = 1;    while(true)    {        digit[len] = num%10;        num /= 10;        if(num == 0)            break;        ++len;    }    return dfs(len, 0, true);}int main(){    memset(table, -1, sizeof(table));    int a, b;    while(scanf("%d%d", &a, &b), a+b)        printf("%d\n", fun(b)-fun(a-1));    return 0;}

HDOJ 3555


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);LL table[25][2][2];int digit[25];LL dfs(int len, int flag1, int flag2, bool bound){    if(len == 0)        return flag2? 1: 0;    if(!bound && table[len][flag1][flag2] != -1)        return table[len][flag1][flag2];    int up = bound? digit[len]: 9;    LL ret = 0;    for(int i = 0; i <= up; ++i)        ret += dfs(len-1, (i == 4? 1: 0), flag2|(flag1 && i == 9? 1: 0), bound && i == up);    if(!bound)        table[len][flag1][flag2] = ret;    return ret;}LL fun(LL num){    int len = 1;    while(true)    {        digit[len] = num%10;        num /= 10;        if(num == 0)            break;        ++len;    }    return dfs(len, 0, 0, true);}int main(){    memset(table, -1, sizeof(table));    int TC;    scanf("%d", &TC);    while(TC--)    {        LL n;        scanf("%I64d", &n);        printf("%I64d\n", fun(n));    }    return 0;}

UESTC 1307

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);int table[15][10];int digit[15];int dfs(int len, int pre, bool bound, bool zero){if(len == 0)return 1;if(!bound && !zero && table[len][pre] != -1)return table[len][pre];int up = bound? digit[len]: 9;int ret = 0;for(int i = 0; i <= up; ++i){if(!zero && abs(i-pre) < 2)continue;ret += dfs(len-1, i, bound && i == up, zero && i == 0);}if(!bound && !zero)table[len][pre] = ret;return ret;}int fun(int num){int len = 1;while(true){digit[len] = num%10;num /= 10;if(num == 0)break;++len;}return dfs(len, 0, true, true);}int main(){memset(table, -1, sizeof(table));int a, b;while(~scanf("%d%d", &a, &b))printf("%d\n", fun(b)-fun(a-1));return 0;}     

常见题型:

hdoj 3652

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);int table[15][13][2][2];int digit[15];int dfs(int len, int divide, int flag1, int flag2, bool bound){    if(len == 0)        return (divide == 0 && flag2? 1: 0);    if(!bound && table[len][divide][flag1][flag2] != -1)        return table[len][divide][flag1][flag2];    int up = bound? digit[len]: 9;    int ret = 0;    for(int i = 0; i <= up; ++i)        ret += dfs(len-1, (divide*10+i)%13, (i == 1? 1: 0), flag2|(i == 3 && flag1? 1: 0), bound && i == up);    if(!bound)        table[len][divide][flag1][flag2] = ret;    return ret;}int fun(int num){    int len = 1;    while(true)    {        digit[len] = num%10;        num /= 10;        if(num == 0)            break;        ++len;    }    return dfs(len, 0, 0, 0, true);}int main(){    memset(table, -1, sizeof(table));    int n;    while(~scanf("%d", &n))        printf("%d\n", fun(n));    return 0;}

hdoj3709 

这个题我是枚举的fix位,因为一个balance number不可能有俩个fix位,所以满足加法原理,不知道有没有更好的办法


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);LL table[20][20][1800];int digit[20];LL dfs(int fix, int len, int presum, bool bound, bool zero){    if(len == 0)        return presum == 0? 1: 0;    if(!bound && !zero && table[fix][len][presum] != -1)        return table[fix][len][presum];    int up = bound? digit[len]: 9;    LL ret = 0;    for(int i = 0; i <= up; ++i)    {        LL temp = presum+(len-fix)*i;        if((zero && i == 0 && fix == len) || temp < 0)            continue;        ret += dfs(fix, len-1, temp, bound && i == up, zero && i == 0);    }    if(!bound && !zero)        table[fix][len][presum] = ret;    return ret;}LL fun(LL num){    int len = 1;    while(true)    {        digit[len] = num%10;        num /= 10;        if(num == 0)            break;        ++len;    }    LL ret = 0;    for(int i = len; i >= 1; --i)        ret += dfs(i, len, 0, true, true);    return ret+1;}int main(){    memset(table, -1, sizeof(table));    int TC;    scanf("%d", &TC);    while(TC--)    {        LL a, b;        scanf("%I64d%I64d", &a, &b);        printf("%I64d\n", fun(b)-(a? fun(a-1): 0));    }    return 0;}


hdoj 3271

数位DP+构造或者二分都可以

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);int table[40][500];int digit[40];int BASE, M;int dfs(int len, int sum, bool bound){    if(len == 0)        return sum == M? 1: 0;    if(!bound && table[len][sum] != -1)        return table[len][sum];    int up = bound? digit[len]: BASE-1;    int ret = 0;    for(int i = 0; i <= up; ++i)    {        int temp = sum+i;        if(temp > M)            continue;        ret += dfs(len-1, temp, bound && i == up);    }    if(!bound)        table[len][sum] = ret;    return ret;}int fun(int num){    int len = 1;    while(true)    {        digit[len] = num%BASE;        num /= BASE;        if(num == 0)            break;        ++len;    }    return dfs(len, 0, true);}int main(){    int Q, X, Y, K, n_case(0);    while(~scanf("%d", &Q))    {        printf("Case %d:\n", ++n_case);        if(Q == 1)        {            memset(table, -1, sizeof(table));            scanf("%d%d%d%d", &X, &Y, &BASE, &M);            if(X > Y)                swap(X, Y);            printf("%d\n", fun(Y)-(X? fun(X-1): 0));        }        else        {            memset(table, -1, sizeof(table));            scanf("%d%d%d%d%d", &X, &Y, &BASE, &M, &K);            if(X > Y)                swap(X, Y);            int l = X, r = Y+1;            int limit = X? fun(X-1): 0;            while(l < r)            {                int m = l+(r-l)/2;                if(fun(m)-limit < K)                    l = m+1;                else                    r = m;            }            if(l == Y+1)                printf("Could not find the Number!\n");            else                printf("%d\n", l);        }    }    return 0;}

HDOJ 3967

枚举拆分位,由于这题算的是拆分种数,所以直接加和即可


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);LL table[20][25];LL pow10[20];int digit[20];int K, sep;LL dfs(int len, LL divide, bool bound, bool zero){    if(len == 0)        return divide? 0: 1;    if(!bound && !zero && table[len][divide] != -1)        return table[len][divide];    int up = bound? digit[len]: 9;    LL ret = 0;    for(int i = 0; i <= up; ++i)    {        if(zero && i == 0 && len == sep+1)            continue;        ret += dfs(len-1, (divide+(len > sep? i*pow10[len-sep-1]: i*pow10[len-1]))%K, bound && i == up, zero && i == 0);    }    if(!bound && !zero)        table[len][divide] = ret;    return ret;}LL fun(LL num){    int len = 1;    while(true)    {        digit[len] = num%10;        num /= 10;        if(num == 0)            break;        ++len;    }    LL ret = 0;    for(int i = len-1; i >= 1; --i)    {        sep = i;        memset(table, -1, sizeof(table));        ret += dfs(len, 0, true, true);    }    return ret;}int main(){    pow10[0] = 1;    for(int i = 1; i < 20; ++i)        pow10[i] = pow10[i-1]*10;    LL A, B;    while(~scanf("%I64d%I64d%d", &A, &B, &K))        printf("%I64d\n", fun(B)-(A? fun(A-1): 0));    return 0;}

HDOJ 3565

求由两个单峰数组成的数字中数位和最大的最大值,注意单峰数的定义,这题不满足区间减法,所以要同时要卡上界和下界(其实这种写法更加通用),state是上一位所在的状态,共有7种,0表示前导0,1表示第一个上升坡,2表示第一个顶点,3表示第一个下降坡,4表示第二个上升坡,5表示第二个顶点,6表示第二个下降坡.

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);bool vis[25][8][10];int table[25][8][10];int digitlow[25], digitup[25];int dfs(int len, int state, int pre, bool lowbound, bool upbound){    if(state == 0 && len < 6)        return -1;    if(len == 0)        return state == 5? 0: -1;    if(!lowbound && !upbound && vis[len][state][pre])        return table[len][state][pre];    int low = lowbound? digitlow[len] : 0, up = upbound? digitup[len]: 9;    int ret = -1;    for(int i = low; i <= up; ++i)    {        int temp;        switch(state)        {        case 0: temp = dfs(len-1, (i == 0? 0: 1), i, lowbound && i == low, upbound && i == up);                if(temp != -1)                    ret = max(ret, temp+i);                break;        case 1: if(i > pre)                {                    temp = dfs(len-1, 1, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                    temp = dfs(len-1, 2, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                }                break;        case 2: if(i < pre)                {                    temp = dfs(len-1, 3, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                }                break;        case 3: if(i < pre)                {                    temp = dfs(len-1, 3, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                }                if(i != 0)                {                    temp = dfs(len-1, 4, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                }                break;        case 4: if(i > pre)                {                    temp = dfs(len-1, 4, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                    temp = dfs(len-1, 5, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                }                break;        case 5:    if(i < pre)                {                    temp = dfs(len-1, 5, i, lowbound && i == low, upbound && i == up);                    if(temp != -1)                        ret = max(ret, temp+i);                }                break;        }    }    if(!lowbound && !upbound)    {        vis[len][state][pre] = true;        table[len][state][pre] = ret;    }    return ret;}int fun(ULL numlow, ULL numup){    int len1, len2;    len1 = 1;    while(true)    {        digitlow[len1] = numlow%10;        numlow /= 10;        if(numlow == 0)            break;        ++len1;    }    len2 = 1;    while(true)    {        digitup[len2] = numup%10;        numup /= 10;        if(numup == 0)            break;        ++len2;    }    for(int i = len1+1; i <= len2; ++i)        digitlow[i] = 0;    return dfs(len2, 0, 0, true, true);}int main(){    int TC, n_case(0);    scanf("%d", &TC);    while(TC--)    {        ULL n1, n2;        scanf("%I64u%I64u", &n1, &n2);        printf("Case %d: ", ++n_case);        int ans = fun(n1, n2);        printf("%d\n", ans == -1? 0: ans);    }    return 0;}


hdoj 3943

数位DP+二分或构造

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);bool vis[25][22][22];ULL table[25][22][22];int digit[25];int X, Y;ULL dfs(int len, int qua1, int qua2, bool bound){    if(len == 0)        return X == qua1 && Y == qua2? 1: 0;    if(!bound && vis[len][qua1][qua2])        return table[len][qua1][qua2];    int up = bound? digit[len]: 9;    ULL ret = 0;    for(int i = 0; i <= up; ++i)    {        int t1 = qua1+(i == 4? 1: 0), t2 = qua2+(i == 7? 1: 0);        if(t1 > X || t2 > Y)            continue;        ret += dfs(len-1, t1, t2, bound && i == up);    }    if(!bound)    {        vis[len][qua1][qua2] = true;        table[len][qua1][qua2] = ret;    }    return ret;}ULL fun(ULL num){    int len = 1;    while(true)    {        digit[len] = num%10;        num /= 10;        if(num == 0)            break;        ++len;    }    return dfs(len, 0, 0, true);}int main(){    int TC, n_case(0);    scanf("%d", &TC);    while(TC--)    {        ULL P, Q;        scanf("%I64u%I64u%d%d", &P, &Q, &X, &Y);        memset(vis, 0, sizeof(vis));        ULL limit = fun(P);        int n;        scanf("%d", &n);        printf("Case #%d:\n", ++n_case);        for(int i = 0; i < n; ++i)        {            ULL l = P+1, r = Q+1, K;            scanf("%I64u", &K);            while(l < r)            {                ULL m = l+(r-l)/2;                if(fun(m)-limit < K)                    l = m+1;                else                    r = m;            }            if(l == Q+1)                printf("Nya!\n");            else                printf("%I64u\n", l);        }    }    return 0;}

hdoj 4389

table[len][i][j][k]表示剩余len位,f(x) = i,已经生成的前缀位%f(x)=j,生成的前缀位的数位和为k最后可以生成的合法数字个数.

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);int table[15][82][82][82];int reg;int digit1[15], digit2[15];int dfs(int len, int divide, int presum, bool lowbound, bool upbound){    if(len == 0)        return divide == 0 && presum == reg? 1: 0;    if(!upbound && !lowbound && table[len][reg][divide][presum] != -1)        return table[len][reg][divide][presum];    int up = upbound? digit2[len]: 9, low = lowbound? digit1[len]: 0;    int ret = 0;    for(int i = low; i <= up; ++i)        ret += dfs(len-1, (divide*10+i)%reg, presum+i, lowbound && i == low, upbound && i == up);    if(!upbound && !lowbound)        table[len][reg][divide][presum] = ret;    return ret;}int fun(int num1, int num2){    int len1 = 1;    while(true)    {        digit1[len1] = num1%10;        num1 /= 10;        if(num1 == 0)            break;        ++len1;    }    int len2 = 1;    while(true)    {        digit2[len2] = num2%10;        num2 /= 10;        if(num2 == 0)            break;        ++len2;    }    for(int i = len1+1; i <= len2; ++i)        digit1[i] = 0;    int ret = 0;    for(int i = 1; i <= 81; ++i)    {        reg = i;        ret += dfs(len2, 0, 0, true, true);    }    return ret;}int main(){    memset(table, -1, sizeof(table));    int TC, n_case(0);    scanf("%d", &TC);    while(TC--)    {        int a, b;        scanf("%d%d", &a, &b);        printf("Case %d: %d\n", ++n_case, fun(a, b));    }    return 0;}

Codeforces 55D. Beautiful numbers 

很明显的数位DP,但状态不好设计,开始想了一种很暴力的状态

table[len][state][r9][r8][r7][r6][r5][r4][r3][r2],表示剩余len位时,(1,2,...9)访问状态为state,已生成的前缀位%i = ri,最后可以得到的合法数字个数,但这复杂度O(18*256*9*8*7*6*5*4*3*2*9)太可观了。。。

后来发现状态r6,r4,r3,r2不是必要的,最后可以由其他状态推出来,可以省略掉,于是复杂度变成了O(18*256*9*8*7*5*9),还是略高,写好后交上去试了一下,3秒卡过


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(1000000007);const ULL LIM(1000000000000000ull);LL table[19][1 << 8][9][8][7][5];int digit1[20], digit2[20];LL dfs(int len, int state, int rem9, int rem8, int rem7, int rem5, bool lowbound, bool upbound){if(len == 0){if((state&(1 << 7)) && rem9)return 0;if((state&(1 << 6)) && rem8)return 0;if((state&(1 << 5)) && rem7)return 0;if((state&(1 << 4)) && (rem9%3 || rem8%2))return 0;if((state&(1 << 3)) && rem5)return 0;if((state&(1 << 2)) && rem8%4)return 0;if((state&(1 << 1)) && rem9%3)return 0;if((state&(1 << 0)) && rem8%2)return 0;return 1;}if(!lowbound && !upbound && table[len][state][rem9][rem8][rem7][rem5] != -1)return table[len][state][rem9][rem8][rem7][rem5];int low = lowbound? digit1[len]: 0, up = upbound? digit2[len]: 9;LL ret = 0;for(int i = low; i <= up; ++i)ret += dfs(len-1, (i >= 2? state|(1 << (i-2)): state), (rem9*10+i)%9, (rem8*10+i)%8, (rem7*10+i)%7, (rem5*10+i)%5, lowbound && i == low, upbound && i == up);if(!lowbound && !upbound)table[len][state][rem9][rem8][rem7][rem5] = ret;return ret;}LL fun(LL num1, LL num2){int len1 = 1;while(true){digit1[len1] = num1%10;num1 /= 10;if(num1 == 0)break;++len1;}int len2 = 1;while(true){digit2[len2] = num2%10;num2 /= 10;if(num2 == 0)break;++len2;}for(int i = len1+1; i <= len2; ++i)digit1[i] = 0;return dfs(len2, 0, 0, 0, 0, 0, true, true);}int main(){memset(table, -1, sizeof(table));int TC;scanf("%d", &TC);while(TC--){LL a, b;scanf("%I64d%I64d", &a, &b);printf("%I64d\n", fun(a, b));}return 0;}

然后就是看题解了,其中应用了俩个性质

1   a = k*b,  则 (n%a)%b = n%b

2   如果 n如果能被 any(a1, a2, ...ak)整除,则有n能被lcm(a1, a2, ...ak)整除

因为lcm(2, 3, 4,...9) = 2520,所以应用这俩个性质就可以设计出一个不错的状态了

table[len][lc][k]表示剩余len位,前缀数位的lcm为lc,生成的前缀%2520为k最后可以得到的合法数字个数

看上去复杂度O(18*2520*2520*9)还是很高,但实际上由于2520的约数个数只有49个,所以lc可以的取值只有49个

这样复杂度就变成了O(18*49*2520*9),空间也可以用离散化压缩,嗯,这样就可以接受了。

题解上还给了一种更加优化的方法,但还不是很理解(果然数学是硬伤%>_<%)。


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(10);const int SIGMA_SIZE(2);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(2520);const ULL LIM(1000000000000000ull);LL table[20][50][2521];int digit1[20], digit2[20];int h[2521];LL gcd(LL a, LL b){LL temp;while(b){temp = a%b;a = b;b = temp;}return a;}LL lcm(LL a, LL b){return a/gcd(a, b)*b;}LL dfs(int len, int lc, int rem, bool lowbound, bool upbound){if(len == 0)return rem%lc? 0: 1;if(!lowbound && !upbound && table[len][h[lc]][rem] != -1)return table[len][h[lc]][rem];int low = lowbound? digit1[len]: 0, up = upbound? digit2[len]: 9;LL ret = 0;for(int i = low; i <= up; ++i)ret += dfs(len-1, i == 0? lc: lcm(lc, i), (rem*10+i)%MOD, lowbound && i == low, upbound && i == up);if(!lowbound && !upbound)table[len][h[lc]][rem] = ret;return ret;}LL fun(LL num1, LL num2){int len1 = 1;while(true){digit1[len1] = num1%10;num1 /= 10;if(num1 == 0)break;++len1;}int len2 = 1;while(true){digit2[len2] = num2%10;num2 /= 10;if(num2 == 0)break;++len2;}for(int i = len1+1; i <= len2; ++i)digit1[i] = 0;return dfs(len2, 1, 0, true, true);}int main(){int count = 0;for(int i = 1; i <= 2520; ++i)if(2520%i == 0)h[i] = count++;memset(table, -1, sizeof(table));int TC;scanf("%d", &TC);while(TC--){LL a, b;scanf("%I64d%I64d", &a, &b);printf("%I64d\n", fun(a, b));}return 0;}

CODECHEF 

Favourite Numbers

http://www.codechef.com/problems/FAVNUM
AC自动机+数位DP

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime> using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque; typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP; const int MAXN(1410);const int SIGMA_SIZE(10);const int MAXM(110);const int MAXE(300010);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const int MOD(2520);const ULL LIM(1000000000000000ull); struct AC{int ch[MAXN][SIGMA_SIZE], f[MAXN];int val[MAXN];int size;inline int idx(char temp){return temp-'0';}void init(){memset(ch[0], 0, sizeof(ch[0]));val[0] = 0;size = 1;} void insert(char *S){int u = 0, id;for(; *S; ++S){id = idx(*S);if(!ch[u][id]){memset(ch[size], 0, sizeof(ch[size]));val[size] = false;ch[u][id] = size++;}u = ch[u][id];}val[u] = 1;} int que[MAXN];int front, back;void construct(){int cur, u;front = back = 0;for(int i = 0; i < SIGMA_SIZE; ++i)if(ch[0][i]){u = ch[0][i];f[u] = 0;que[back++] = u;}while(front < back){cur = que[front++];for(int i = 0; i < SIGMA_SIZE; ++i){u = ch[cur][i];if(u){f[u] = ch[f[cur]][i];val[u] |= val[f[u]];que[back++] = u;}elsech[cur][i] = ch[f[cur]][i];}}}}; AC ac; LL table[20][MAXN][2];int digit1[20], digit2[20]; LL dfs(int len, int u, int flag, bool lowbound, bool upbound, bool zero){if(len == 0)return flag? 1: 0;if(!lowbound && !upbound && !zero && table[len][u][flag] != -1)return table[len][u][flag];int low = lowbound? digit1[len]: 0, up = upbound? digit2[len]: 9;LL ret = 0;for(int i = low; i <= up; ++i)if(zero && i == 0 && len > 1)ret += dfs(len-1, 0, flag, lowbound && i == low, upbound && i == up, true);elseret += dfs(len-1, ac.ch[u][i], flag|(ac.val[ac.ch[u][i]]), lowbound && i == low, upbound && i == up, zero && i == 0);if(!lowbound && !upbound && !zero)table[len][u][flag] = ret;return ret;} LL fun(LL num1, LL num2){int len1 = 1;while(true){digit1[len1] = num1%10;num1 /= 10;if(num1 == 0)break;++len1;}int len2 = 1;while(true){digit2[len2] = num2%10;num2 /= 10;if(num2 == 0)break;++len2;}for(int i = len1+1; i <= len2; ++i)digit1[i] = 0;return dfs(len2, 0, 0, true, true, true);} char str[20]; int main(){LL a, b, K;int n;while(cin >> a >> b >> K >> n){ac.init();for(int i = 0; i < n; ++i){cin >> str;ac.insert(str);}ac.construct();memset(table, -1, sizeof(table));LL l = a, r = b+1;while(l < r){LL m = l+(r-l)/2;if(fun(a, m) < K)l = m+1;elser = m;}if(l == b+1)cout << "no such number\n";elsecout << l << "\n";}return 0;}

Fast Bit Calculations lightoj 1032

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::istringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(200010);const int MAXM(10010);const int MAXE(10010);const int MAXH(19);const int INFI(2000000000);const int MOD(1000000007);const ULL BASE(31);const LL LIM(10000000);const int INV(-10000);LL table[33][33][2];int digit1[33], digit2[33];LL dfs(int len, int presum, int flag, bool lowbound, bool upbound){if(len == 0)return presum;if(!lowbound && !upbound && table[len][presum][flag] != -1)return table[len][presum][flag];int low = lowbound? digit1[len]: 0, up = upbound? digit2[len]: 1;LL ret = 0;for(int i = low; i <= up; ++i)ret += dfs(len-1, presum+(i&flag), i, lowbound && i == low, upbound && i == up);if(!lowbound && !upbound)table[len][presum][flag] = ret;return ret;}LL fun(int num1, int num2){int len1 = 1;while(true){digit1[len1] = num1&1;num1 >>= 1;if(num1 == 0)break;++len1;}int len2 = 1;while(true){digit2[len2] = num2&1;num2 >>= 1;if(num2 == 0)break;++len2;}for(int i = len1+1; i <= len2; ++i)digit1[i] = 0;return dfs(len2, 0, 0, true, true);}int main(){memset(table, -1, sizeof(table));int TC, n_case(0);scanf("%d", &TC);while(TC--){int n;scanf("%d", &n);printf("Case %d: %lld\n", ++n_case, fun(0, n));}return 0;}



BALNUM spoj10606


#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::stringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> PAIR;typedef multimap<int, int> MMAP;const int MAXN(1510);const int MAXM(5010);const int MAXE(10010);const int HSIZE(13131);const int SIGMA_SIZE(26);const int MAXH(19);const int INFI((INT_MAX-1) >> 1);const ULL BASE(31);const LL LIM(10000000);const int INV(-10000);int hash[1024][1024];LL table[21][60010];int lowdig[21], updig[21];LL dfs(int len, int state1, int state2, bool zero, bool lowbound, bool upbound){if(len == 0){for(int i = 0; i <= 9; ++i)if((state1&(1 << i)) && ((state2&(1 << i))^((i&1) << i)) == 0)return 0;return 1;}if(!zero && !lowbound && !upbound && table[len][hash[state1][state2]] != -1)return table[len][hash[state1][state2]];int low = lowbound? lowdig[len]: 0;int up = upbound? updig[len]: 9;LL temp = 0;for(int i = low; i <= up; ++i)if(zero && i == 0)temp += dfs(len-1, state1, state2, true, lowbound && i == low, upbound && i == up);elsetemp += dfs(len-1, state1|(1 << i),  state2^(1 << i), false, lowbound && i == low, upbound && i == up);if(!zero && !lowbound && !upbound)table[len][hash[state1][state2]] = temp;return temp;}LL fun(ULL l, ULL u){int len1 = 1;while(true){lowdig[len1] = l%10;l /= 10;if(!l)break;++len1;}int len2 = 1;while(true){updig[len2] = u%10;u /= 10;if(!u)break;++len2;}for(int i = len1+1; i <= len2; ++i)lowdig[i] = 0;return dfs(len2, 0, 0, true, true, true);}int main(){int cnt = 0;for(int i = 0; i < 1024; ++i)for(int j = 0; j < 1024; ++j){bool flag(true);for(int k = 0; k <= 9; ++k)if(!(i&(1 << k)) && (j&(1 << k))){flag = false;break;}if(flag) hash[i][j] = cnt++;}memset(table, -1, sizeof(table));int TC;scanf("%d", &TC);ULL a, b;while(TC--){scanf("%llu%llu", &a, &b);printf("%lld\n", fun(a, b));}return 0;}

俩个回文数字题:

需要注意的是回文定义的状态还有无后效性(只对数字的前一半进行DP)

poj2402

http://poj.org/problem?id=2402

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>#include <bitset>#include <iomanip>//#pragma comment(linker, "/STACK:102400000,102400000")using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::stringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;using std::unique;using std::lower_bound;using std::random_shuffle;using std::bitset;using std::upper_bound;using std::multiset;using std::ios;using std::make_heap;using std::push_heap;using std::pop_heap;typedef long long LL;typedef unsigned long long ULL;typedef unsigned UN;typedef pair<ULL, ULL> PAIR;typedef multimap<int, int> MMAP;typedef long double LF;const int MAXN(1510);const int MAXM(40010);const int MAXE(10010);const int MAXK(6);const int HSIZE(13131);const int SIGMA_SIZE(26+11);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const ULL BASE(31);const LL LIM(1e13);const int INV(-10000);const int MOD(1000000007);const double EPS(1e-7);const LF PI(acos(-1.0));template<typename T> inline bool checkmax(T &a, T b){if(b > a) { a = b; return true;} return false;}template<typename T> inline bool checkmin(T &a, T b){if(b < a) { a = b; return true;} return false;}template<typename T> inline T ABS(T a){return a < 0? -a: a;}template<typename T> inline bool EZ(T a){return ABS(a) < EPS;}LL dp[20][20];int dig[20], tdig[20];LL dfs(int len, int tl, bool bound, bool zero){if(len+1 == tl/2)   //通过前一半可以得出结果{if(!zero && !bound) return 1;int add = (tl&1)? 2: 1;for(int i = 0; i <= len; ++i) tdig[len-i] = tdig[len+i+add];for(int i = len; i >= 0; --i){if(tdig[i] < dig[i]) return 1;if(tdig[i] > dig[i]) return 0;}return 1;}if(!zero && !bound && dp[len][tl] != -1) return dp[len][tl];int up = bound? dig[len]: 9;LL ret = 0;for(int i = 0; i <= up; ++i){tdig[len] = i;ret += dfs(len-1, tl? tl: (zero && i == 0? 0: len+1), bound && i == up, zero && i == 0);}if(!zero && !bound && len+1 > tl/2) dp[len][tl] = ret; //只对前一半dpreturn ret;}LL fun(LL n){int len = 0;while(true){dig[len] = n%10;n /= 10;if(n == 0) break;++len;}return dfs(len, 0, true, true)-1;}int main(){int n;memset(dp, -1, sizeof(dp));while(scanf("%d", &n), n){LL lo = 1, hi = 1LL << 62;while(lo < hi){LL mi = lo+(hi-lo)/2;if(fun(mi) < n) lo = mi+1;else hi = mi;}printf("%I64d\n", lo);}return 0;}

uestc1191

http://acm.uestc.edu.cn/problem.php?pid=1191

#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <queue>#include <algorithm>#include <vector>#include <cstring>#include <stack>#include <cctype>#include <utility>   #include <map>#include <string>  #include <climits> #include <set>#include <string>    #include <sstream>#include <utility>   #include <ctime>#include <bitset>#include <iomanip>//#pragma comment(linker, "/STACK:102400000,102400000")using std::priority_queue;using std::vector;using std::swap;using std::stack;using std::sort;using std::max;using std::min;using std::pair;using std::map;using std::string;using std::cin;using std::cout;using std::set;using std::queue;using std::string;using std::stringstream;using std::make_pair;using std::getline;using std::greater;using std::endl;using std::multimap;using std::deque;using std::unique;using std::lower_bound;using std::random_shuffle;using std::bitset;using std::upper_bound;using std::multiset;using std::ios;using std::make_heap;using std::push_heap;using std::pop_heap;typedef long long LL;typedef unsigned long long ULL;typedef unsigned UN;typedef pair<ULL, ULL> PAIR;typedef multimap<int, int> MMAP;typedef long double LF;const int MAXN(1510);const int MAXM(40010);const int MAXE(10010);const int MAXK(6);const int HSIZE(13131);const int SIGMA_SIZE(26+11);const int MAXH(18);const int INFI((INT_MAX-1) >> 1);const ULL BASE(31);const LL LIM(1e13);const int INV(-10000);const int MOD(1000000007);const double EPS(1e-7);const LF PI(acos(-1.0));template<typename T> inline bool checkmax(T &a, T b){if(b > a) { a = b; return true;} return false;}template<typename T> inline bool checkmin(T &a, T b){if(b < a) { a = b; return true;} return false;}template<typename T> inline T ABS(T a){return a < 0? -a: a;}template<typename T> inline bool EZ(T a){return ABS(a) < EPS;}LL dp[22][22];int dig[22], tdig[22];LL dfs(int len, int tl, bool bound, bool zero){if(len+1 == tl/2){if(!zero && !bound) return 1;int add = (tl&1)? 2: 1;for(int i = 0; i <= len; ++i) tdig[len-i] = tdig[len+i+add];for(int i = len; i >= 0; --i){if(tdig[i] < dig[i]) return 1;if(tdig[i] > dig[i]) return 0;}return 1;}if(!zero && !bound && dp[len][tl] != -1) return dp[len][tl];int up = bound? dig[len]: 9;LL ret = 0;for(int i = 0; i <= up; ++i){tdig[len] = i;if(zero){if(i != 0 && ((len+1)&1) == 0) continue;ret += dfs(len-1, i == 0? 0: len+1, bound && i == up, i == 0);}else{if(i == tdig[len+1]) continue;ret += dfs(len-1, tl, bound && i == up, false);}}if(!zero && !bound && len+1 > tl/2) dp[len][tl] = ret;return ret;}LL fun(ULL n){int len = 0;while(true){dig[len] = n%10;n /= 10;if(n == 0) break;++len;}return dfs(len, 0, true, true);}int main(){memset(dp, -1, sizeof(dp));int TC;scanf("%d", &TC);while(TC--){ULL a, b;scanf("%llu%llu", &a, &b);LL re = fun(b)-(a? fun(a-1): 0);printf("%lld\n", re);}return 0;}     


原创粉丝点击