数位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;}
数位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;}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;}
- 数位DP题集
- 数位DP 题集
- 数位dp题集
- 数位DP 题集
- 数位DP题集
- 数位dp
- 数位DP
- 数位DP
- 数位dp
- 数位dp
- 数位dp
- 数位DP
- 数位dp
- 数位DP
- 【数位DP】
- 数位DP
- 数位dp
- 数位dp
- JavaScript学习笔记(三十) 代码复用模式
- foj 1055 赋值问题 &&1723 我就不信你能找得到 &&1063 三维扫描
- chkdsk磁盘修复
- 在viewpad 10pro上运行linux
- \tutorial_code\ShapeDescriptors
- 数位DP题集
- 唯有自主创新,艰苦卓绝的干出一番事业,才有被尊重的可能
- DB2常用命令大全
- cocos2d-x 回调函数详解
- UTF-8解码
- 疯狂JAVA讲义---第十二章:Swing编程(七)JTree树
- MapReduce:详解Shuffle过程
- Directshow9.0--开发的程序在windows7下面图像显示不正常
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调