数位dp合集w
【BZOJ1026】【SCOI2009】windy数
传送门~:http://www.lydsy.com/JudgeOnline/problem.php?id=1026
数位dp傻题QaQ
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 int f[15][15], A, B, da[15]; 7 void get_ready(){ 8 for (int i = 0; i <= 9; i++) f[1][i] = 1; 9 for (int i = 2; i <= 10; i++){ 10 for (int j = 0; j <= 9; j++) { 11 for (int k = 0; k <= 9; k++) { 12 if (abs(j-k) >= 2) f[i][j] += f[i-1][k]; 13 } 14 } 15 } 16 } 17 18 int calc(int a){ 19 if (a == 0) return 0; 20 int ret = 0, len = 0; 21 do{ 22 da[++len] = a % 10; 23 a /= 10; 24 }while(a); 25 for (int i = 1; i < len; i++) 26 for (int j = 1; j <= 9; j++) 27 ret += f[i][j]; 28 for (int i = 1; i < da[len]; i++) ret += f[len][i]; 29 for (int i = len-1; i > 0; i--) { 30 for (int j = 0; j < da[i]; j++) 31 if (abs(j-da[i+1]) >= 2) ret += f[i][j]; 32 if (abs(da[i]-da[i+1]) < 2) break; 33 } 34 return ret; 35 } 36 37 int main(){ 38 freopen("bzoj1026.in", "r", stdin); 39 freopen("bzoj1026.out", "w", stdout); 40 get_ready(); 41 scanf("%d%d", &A, &B); 42 printf("%d\n", calc(B+1) - calc(A)); 43 return 0; 44 }
【HDU3652】B-number
传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12990
题意:问1~n中包含"13"序列且能被13整除的数有多少个。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 6 using namespace std; 7 int n, da[30]; 8 int f[15][3][15], vis[15][3][15]; 9 10 int dp(int len, int up, int type, int mod){ 11 if (!len) return (!mod && type == 2); 12 if (!up && vis[len][type][mod]) return f[len][type][mod]; 13 int ret = 0, top = up ? da[len] : 9; 14 for (int i = 0; i <= top; i++){ 15 int x = type; 16 if (type == 0 && i == 1) x = 1; 17 if (i != 1 && type == 1) x = 0; 18 if (type == 1 && i == 3) x = 2; 19 ret += dp(len-1, up&&(i==top), x, (mod*10 + i)%13); 20 } 21 if (!up){ 22 vis[len][type][mod] = 1; 23 f[len][type][mod] = ret; 24 } 25 return ret; 26 } 27 28 int calc(int a){ 29 int len = 0; 30 while (a){ 31 da[++len] = a % 10; 32 a /= 10; 33 } 34 return dp(len, 1, 0, 0); 35 } 36 37 int main(){ 38 freopen("hdu3652.in", "r", stdin); 39 freopen("hdu3652.out", "w", stdout); 40 int l = 0; 41 while (~scanf("%d", &n)){ 42 memset(f, 0, sizeof(f)); 43 memset(vis, 0, sizeof(vis)); 44 printf("%d\n", calc(n)); 45 } 46 // for (int i = 1; i <= 10010; i++) 47 // cout<<i<<" "<<calc(i)<<" "<<i%p<<endl; 48 return 0; 49 }
【HDU3709】Balanced Number
传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=41280
题意:题目先给出平衡数的概念:数n以数n中的某个位为支点,每个位上的数权值为(数字xi*(posi - 支点的posi)),如果数n里有一个支点使得所有数权值之和为0那么她就是平衡数。比如4139,以3为支点,左边 = 4 * (4 - 2) + 1 * (3 - 2) = 9,右边 = 9 * (1 - 2) = -9,左边加右边为0,所以4139是平衡数。现在给出一个区间[l,r],问区间内平衡数有多少个?
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #define LL long long 6 using namespace std; 7 int da[20]; 8 LL l, r; 9 LL f[20][20][2100]; 10 11 LL dp(int len, int pos, int up, int l){ 12 if (!len || l < 0) return l == 0; 13 if (!up && f[len][pos][l] != -1) return f[len][pos][l]; 14 LL ret = 0ll; 15 int top = up ? da[len] : 9; 16 for (int i = 0; i <= top; i++) { 17 ret += dp(len-1, pos, up&&(i==top), l+(len-pos)*i); 18 } 19 if (!up) f[len][pos][l] = ret; 20 return ret; 21 } 22 23 LL calc(LL a){ 24 int len = 0; 25 LL ret = 0ll; 26 while(a){ 27 da[++len] = (int) (a % 10); 28 a /= 10ll; 29 } 30 for (int i = 1; i <= len; i++) { 31 ret += dp(len, i, 1, 0); 32 } 33 return ret-(LL)len+1; 34 } 35 36 int main(){ 37 freopen("hdu3709.in", "r", stdin); 38 freopen("hdu3709.out", "w", stdout); 39 int T; 40 scanf("%d", &T); 41 memset(f, -1, sizeof(f)); 42 while (T--){ 43 scanf("%lld%lld", &l, &r); 44 printf("%lld\n", calc(r) - calc(l-1)); 45 } 46 return 0; 47 }
【HDU3886】 Final Kichiku “Lanlanshu”
传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=21534
题意:A,B之间有多少个数,满足给定字符串的趋势,字符串由“/”“-”“\”这3个字符构成,分别表示上升,不变和下降。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 using namespace std; 6 const int p = 1e8; 7 char ca[110], cb[110], c[110]; 8 int lenK, lenC; 9 int da[110], K[110]; 10 int f[110][110][10]; 11 12 bool getk(char s, int i, int las){ 13 if (s == '-') return i == las; 14 if (s == '/') return i > las; 15 if (s == '\\') return i < las; 16 return 0; 17 } 18 19 int dp(int len, int up, int zero, int k, int las){ 20 //cout<<k<<endl; 21 if (!len) return k == lenK; 22 if (!up && !zero && f[len][k][las]!=-1) return f[len][k][las]; 23 int ret = 0, top = up ? da[len] : 9; 24 for (int i = 0; i <= top; i++){ 25 if (zero) { 26 if (!i) ret += dp(len-1, up&&(i==top), 1, 0, -1), ret %= p; 27 else ret += dp(len-1, up&&(i==top), 0, 0, i), ret %= p; 28 } 29 else { 30 if(getk(c[k], i, las) && k < lenK) 31 ret += dp(len-1, up&&(i==top), 0, k+1, i), ret %= p; 32 else if((k > 0 && getk(c[k-1], i, las))) 33 ret += dp(len-1, up&&(i==top), 0, k, i), ret %= p; 34 } 35 } 36 if (!up && !zero) f[len][k][las] = ret; 37 return ret; 38 } 39 40 int calc(char *ch, int x){ 41 int len = strlen(ch); 42 for (int i = 0; i < len; i++) da[len-i] = ch[i]-'0'; 43 while (!da[len] && len > 1) len--; 44 if (len == 1 && !da[len]) return 0; 45 if (x) { 46 da[1]--; 47 for (int i = 1; i < len; i++) 48 if (da[i] < 0) da[i] += 10, da[i+1]--; 49 while (!da[len] && len > 1) len--; 50 } 51 if (len == 1 && !da[len]) return 0; 52 //cout<<dp(len, 1, 1, 1, -2)<<endl; 53 return dp(len, 1, 1, 0, -1); 54 } 55 56 int main(){ 57 freopen("hdu3886.in", "r", stdin); 58 freopen("hdu3886.out", "w", stdout); 59 while (~scanf("%s%s%s",c, ca, cb)){ 60 memset(f, -1, sizeof(f)); 61 lenK = strlen(c); 62 printf("%08d\n",(calc(cb, 0) - calc(ca, 1) + p) % p); 63 } 64 return 0; 65 }
【HDU3943】K-th nya number
传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22331
题意:求出区间 (P,Q] 中找到第K个满足条件的数,条件是该数包含X个4和Y个7。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #define MaxN 110 5 #define LL long long 6 using namespace std; 7 LL p, q, ls; 8 LL f[30][2][21][21]; 9 int da[30], x, y; 10 int vis[30][2][21][21]; 11 12 LL dp(int len, int up, int zero, int a, int b){ 13 if (!len) return (!a && !b); 14 if (a < 0 || b < 0) return 0ll; 15 if (!up && vis[len][zero][a][b]) return f[len][zero][a][b]; 16 LL ret = 0ll; 17 int top = up ? da[len] : 9; 18 if (zero) ret = dp(len - 1, 0, 1, a, b); 19 for (int i = zero; i <= top; i++){ 20 ret += dp(len-1, up&&(i==top), 0, a-(i==4), b-(i==7)); 21 } 22 if (!up){ 23 f[len][zero][a][b] = ret; 24 vis[len][zero][a][b] = 1; 25 } 26 return ret; 27 } 28 29 LL calc(LL a){ 30 int len = 0; 31 while (a){ 32 da[++len] = (int) (a % 10); 33 a /= 10ll; 34 } 35 return dp(len, 1, 1, x, y); 36 } 37 38 void Solve(LL k){ 39 LL l = p, r = q, mid; 40 while (l + 1 < r){ 41 mid = (l + r) / 2; 42 if ((calc(mid)-ls) < k) l = mid; 43 else r = mid; 44 } 45 if ((calc(r)-ls) == k) printf("%lld\n", r); 46 else printf("Nya!\n"); 47 } 48 49 int main(){ 50 freopen("hdu3943.in", "r", stdin); 51 freopen("hdu3943.out", "w", stdout); 52 int T, query, l = 0; 53 LL k; 54 scanf("%d", &T); 55 while (T--){ 56 scanf("%lld%lld%d%d", &p, &q, &x, &y); 57 scanf("%d", &query); 58 ls = calc(p); 59 printf("Case #%d:\n", ++l); 60 for (int i = 1; i <= query; i++) { 61 scanf("%lld", &k); 62 Solve(k); 63 } 64 } 65 return 0; 66 }
【HDU4352】XHXJ's LIS
传送门:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=30872
题意:问L到R,各位数字组成的最长上升子序列的长度为K的数的个数。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #define LL long long 6 using namespace std; 7 int T, k; 8 int da[30]; 9 LL f[30][1<<10][11]; 10 LL l, r; 11 12 int gets(int s, int x){ 13 for (int i = x; i <= 9; i++){ 14 if (s & (1<<i)) return (s^(1<<i)) | (1<<x); 15 } 16 return s|(1<<x); 17 } 18 19 int getk(int x){ 20 int ret = 0; 21 while(x){ 22 ret += x & 1; 23 x >>= 1; 24 } 25 return ret; 26 } 27 28 LL dp(int len, int up, int zero, int s){ 29 if (!len) return getk(s) == k; 30 if (!up && f[len][s][k] != -1) return f[len][s][k]; 31 LL ret = 0ll; 32 int top = up ? da[len] : 9; 33 if (zero) ret = dp(len-1, 0, 1, 0); 34 for (int i = zero; i <= top; i++){ 35 ret += dp(len-1, up&&(i==top), 0, gets(s, i)); 36 } 37 if (!up) f[len][s][k] = ret; 38 return ret; 39 } 40 41 LL calc(LL a){ 42 int len = 0; 43 while (a){ 44 da[++len] = (int) (a % 10); 45 a /= 10ll; 46 } 47 return dp(len, 1, 1, 0); 48 } 49 50 int main(){ 51 freopen("hdu4352.in", "r", stdin); 52 freopen("hdu4352.out", "w", stdout); 53 scanf("%d", &T); 54 memset(f, -1, sizeof(f)); 55 for (int i = 1; i <= T; i++){ 56 scanf("%lld%lld%d", &l, &r, &k); 57 printf("Case #%d: %lld\n", i, calc(r)-calc(l-1)); 58 } 59 return 0; 60 }
【SCOI2014】【BZOJ3598】方伯伯的商场之旅
看这里看这里whttp://www.cnblogs.com/Lukaluka/p/5206022.html
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #define LL long long 6 using namespace std; 7 const int MaxN = 65; 8 int u[MaxN], d[MaxN], LEN; 9 LL l, r, k; 10 LL f[MaxN][2][2], g[MaxN][1600], ans[2333], sum[MaxN][2][2]; 11 12 LL dp(int len, int up, int down){ 13 if (!len) { sum[len][up][down] = 1; return 0; } 14 if (f[len][up][down]!= -1) return f[len][up][down]; 15 LL ret = 0ll, num = 0ll; 16 int top = up ? u[len] : (int)k-1, bot = down ? d[len] : 0; 17 for (int i = bot; i <= top; i++){ 18 int p1 = (i==top)&&up, p2 = i==bot&&down; 19 ret += dp(len-1, p1, p2) + i*(len-1)*sum[len-1][p1][p2]; 20 num += sum[len-1][p1][p2]; 21 } 22 f[len][up][down] = ret, sum[len][up][down] = num; 23 return ret; 24 } 25 26 LL calc(LL x, LL y){ 27 int len = 0, len2 = 0; 28 while(x){ 29 u[++len] = (int) (x%k); 30 x /= k; 31 } 32 while(y){ 33 d[++len2] = (int) (y%k); 34 y /= k; 35 } 36 LEN = len; 37 return dp(len, 1, 1); 38 } 39 40 LL dfs(int len, int up, int down, int p, int s){ 41 if (!len) return (LL)s; 42 if (!up && !down && g[len][s] != -1) return g[len][s]; 43 LL ret = 0; 44 int top = up ? u[len] :(int)k-1, bot = down ? d[len] : 0; 45 for (int i = bot; i <= top; i++){ 46 int x = (len >= p ? 1 : -1), c = i==top&&up, d = i==bot&&down; 47 x = x*i + s; 48 if (x < 0) break; 49 ret += dfs(len-1, c, d, p, x); 50 } 51 if (!up && !down) g[len][s] = ret; 52 return ret; 53 } 54 55 void Solve(){ 56 memset(f, -1ll, sizeof(f)); 57 LL ret = calc(r, l); 58 //cout<<ret<<endl; 59 LL dec = 0ll; 60 for (int i = 2; i <= LEN; i++){ 61 memset(g, -1ll, sizeof(g)), dec += dfs(LEN, 1, 1, i, 0); 62 } 63 cout<<ret - dec; 64 } 65 66 int main(){ 67 cin>>l>>r>>k; 68 Solve(); 69 return 0; 70 }
啊TuT待更