强烈推荐记忆化搜索写法,好写,通用。
入门题:
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;
}
数位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
#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;
}