数位DP题集

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

入门题:

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;
				}
				else
					ch[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);
		else
			ret += 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;
			else
				r = m;
		}
		if(l == b+1)
			cout << "no such number\n";
		else
			cout << 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);
		else
			temp += 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; //只对前一半dp
	return 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;
}
 				    


你可能感兴趣的:(数位DP题集)