[kuangbin带你飞]专题十五 数位DP

来源:互联网 发布:淘宝网孕妇秋装套装 编辑:程序博客网 时间:2024/05/16 10:26
ACodeForces 55DBeautiful numbers#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int MAXN = 25;const int MOD = 2520;//1~9的lcm为2520long long dp[MAXN][MOD][48];int index[MOD + 10];//记录1~9的最小公倍数int bit[MAXN];int lcm(int a, int b){return a / __gcd(a, b)*b;}void init(){int num = 0;for (int i = 1; i <= MOD; i++)if (MOD%i == 0)index[i] = num++;}long long dfs(int pos, int preSum, int preLcm, bool flag){if (pos == -1)return preSum%preLcm == 0;if (!flag && dp[pos][preSum][index[preLcm]] != -1)return dp[pos][preSum][index[preLcm]];long long ans = 0;int end = flag ? bit[pos] : 9;//上界for (int i = 0; i <= end; i++){int nowSum = (preSum * 10 + i) % MOD;int nowLcm = preLcm;if (i)nowLcm = lcm(nowLcm, i);ans += dfs(pos - 1, nowSum, nowLcm, flag && i == end);}if (!flag)dp[pos][preSum][index[preLcm]] = ans;return ans;}long long calc(long long x){int pos = 0;while (x){bit[pos++] = x % 10;x /= 10;}return dfs(pos - 1, 0, 1, 1);}int main(){int T;long long l, r;init();memset(dp, -1, sizeof(dp));scanf("%d", &T);while (T--){scanf("%lld%lld", &l, &r);printf("%lld\n", calc(r) - calc(l - 1));}return 0;}BHDU 4352XHXJ's LIS#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define LL long longusing namespace std;LL dp[20][1 << 10][11];int k, bit[20];int update(int x, int s){for (int i = x; i<10; i++){if (s&(1 << i))return (s ^ (1 << i)) | (1 << x);}return s | (1 << x);}int getK(int s){int cnt = 0;while (s){if (s & 1)cnt++;s >>= 1;}return cnt;}LL dfs(int pos, int s, bool e, bool z) //e为上界,z记录前面的是否都为0,1代表全为0{if (!pos)return getK(s) == k;if (!e && dp[pos][s][k] != -1)return dp[pos][s][k];int digit = e ? bit[pos] : 9;LL ans = 0;for (int i = 0; i <= digit; i++){ans += dfs(pos - 1, (z && (i == 0)) ? 0 : update(i, s), e&&i == digit, z && (i == 0));}if (!e)dp[pos][s][k] = ans;return ans;}LL solve(LL n){int len = 0;while (n){bit[++len] = n % 10;n /= 10;}return dfs(len, 0, 1, 1);}int main(){int cas = 1, t;scanf("%d", &t);memset(dp, -1, sizeof dp);while (t--){LL a, b;cin >> a >> b >> k;printf("Case #%d: %I64d\n", cas++, solve(b) - solve(a - 1));}return 0;}HDU 2089不要62#include<iostream>#include<cstdio>using namespace std;int dp[10][10];int d[10];void init(){dp[0][0] = 1;for (int i = 1; i <= 7; ++i)for (int j = 0; j <= 9; ++j)for (int k = 0; k <= 9; ++k)if (j != 4 && !(j == 6 && k == 2))dp[i][j] += dp[i - 1][k];}int solve(int n){int ans = 0;int len = 0;while (n){++len;d[len] = n % 10;n /= 10;}d[len + 1] = 0;for (int i = len; i >= 1; --i){for (int j = 0; j < d[i]; ++j){if (d[i + 1] != 6 || j != 2)ans += dp[i][j];}if (d[i] == 4 || (d[i + 1] == 6 && d[i] == 2))break;}return ans;}int main(){int m, n;init();while (scanf("%d%d", &m, &n) == 2){if (n == 0 && m == 0) break;printf("%d\n", solve(n + 1) - solve(m));}return 0;}DHDU 3555Bomb#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;typedef __int64 LL;LL dp[27][3];int c[27];//dp[i][j]:长度为i的数的第j种状态//dp[i][0]:长度为i但是不包含49的方案数//dp[i][1]:长度为i且不含49但是以9开头的数字的方案数//dp[i][2]:长度为i且包含49的方案数void init(){memset(dp, 0, sizeof(dp));dp[0][0] = 1;for (int i = 1; i <= 20; i++){dp[i][0] = dp[i - 1][0] * 10 - dp[i - 1][1];//所有情况减去开头为4的情况dp[i][1] = dp[i - 1][0] * 1;//这个随便dp[i][2] = dp[i - 1][2] * 10 + dp[i - 1][1];//已经有的随便,有9的就加上4就行}}int cal(LL n){int k = 0;memset(c, 0, sizeof(c));while (n){c[++k] = n % 10;n /= 10;}c[k + 1] = 0;return k;}void solve(int len, LL n){int flag = 0;                   //标记是否出现过49LL ans = 0;for (int i = len; i >= 1; i--){ans += c[i] * dp[i - 1][2];       //为什么乘以c[i]因为可以有0~i-1个也就是i个if (flag)                    //如果之前出现过49那么直接乘以没有出现49的情况,因为初始时候已经乘以了有49的情况ans += c[i] * dp[i - 1][0];else if (c[i] > 4)           //这一位前面没有挨着49,但c[i]比4大,那么当这一位填4的时候,要加上dp[i-1][1]ans += dp[i - 1][1];if (c[i + 1] == 4 && c[i] == 9)flag = 1;}printf("%I64d\n", ans);}int main(){int t;LL n;init();scanf("%d", &t);while (t--){scanf("%I64d", &n);int len = cal(n + 1);solve(len, n);}return 0;}EPOJ 3252Round Numbers#include<cstdio>#include<cstring>int dp[50][50][50], digit[50], s, t;//dfs间接枚举所有情况int dfs(int pos, int zero, int one, int lead, int limit)//limit判断上一位数字是否达到上界,lead有没有1出现{if (!pos)return zero >= one;if (!limit&&dp[pos][zero][one] != -1)return dp[pos][zero][one];int up = limit ? digit[pos] : 1, ans = 0;for (int i = 0; i <= up; i++)ans += dfs(pos - 1, lead ? zero + (i == 0) : 0, one + (i == 1), lead || i == 1, limit&&i == up);return  limit ? ans : dp[pos][zero][one] = ans;}int cal(int n){int len = 0;while (n)    digit[++len] = n % 2, n >>= 1;return dfs(len, 0, 0, 0, 1);}int main(){memset(dp, -1, sizeof(dp));scanf("%d%d", &s, &t);printf("%d\n", cal(t) - cal(s - 1));}FHDU 3709Balanced Number#include <iostream>#include<cstdio>#include<cstring>using namespace std;long long dp[30][30][3000];int num[30];long long dfs(int pos, int center, int sum, bool flag){if (pos == 0) return sum == 0;if (sum<0) return 0;if (!flag&&dp[pos][center][sum] != -1) return dp[pos][center][sum];long long ans = 0;int maxn = flag ? num[pos] : 9;for (int i = 0; i <= maxn; i++){ans += dfs(pos - 1, center, sum + i*(pos - center), i == maxn&&flag);}if (!flag) dp[pos][center][sum] = ans;return ans;}long long cal(long long x){long long ans = 0;int pos = 0;while (x){num[++pos] = x % 10;x /= 10;}for (int i = 1; i <= pos; i++)ans += dfs(pos, i, 0, 1);return ans - pos + 2;}int main(){int t;long long n, m;memset(dp, -1, sizeof(dp));scanf("%d", &t);while (t--){scanf("%I64d%I64d", &n, &m);printf("%I64d\n", cal(m) - cal(n - 1));}return 0;}GHDU 3652 B - number#include<iostream>#include<cstdio>#include<cstring>#define mod 13using namespace std;int dp[20][15][4];int num[20];int dfs(int pos, int mo, int status, bool limit){if (!pos)  return status == 2 && mo == 0;if (!limit&&dp[pos][mo][status] != 0) return dp[pos][mo][status];int end = limit ? num[pos] : 9;int sum = 0;for (int i = 0; i <= end; i++){int a = mo;int flag = status;if (flag == 0 && i == 1) flag = 1;if (flag == 1 && i == 3) flag = 2;if (flag == 1 && i != 1 && i != 3) flag = 0;sum += dfs(pos - 1, (a * 10 + i) % mod, flag, limit&&i == end);}return limit ? sum : dp[pos][mo][status] = sum;}int cal(int n){int pos = 1;memset(dp, 0, sizeof dp);while (n>0){num[pos++] = n % 10;n /= 10;}return dfs(pos - 1, 0, 0, true);}int main(){int n;while (~scanf("%d", &n)){printf("%d\n", cal(n));}return 0;}HHDU 4734F(x)#include<iostream>#include<cstdio>#include<cstring>using namespace std;int digit[20], dp[20][10000], t, a, b, ans, cas = 1;//dp[i][j]表示一共i位的数其中小于j的个数int dfs(int pos, int st, bool limit){if (pos == 0)  return st >= 0;if (!limit&&dp[pos][st] != -1) return dp[pos][st];int end = limit ? digit[pos] : 9, ans = 0;for (int i = 0; i <= end; i++)ans += dfs(pos - 1, st - i*(1 << (pos - 1)), limit&&i == end);if (!limit)  dp[pos][st] = ans;return ans;}int f(int x){int sum = 0, cnt = 0;while (x)    sum += (x % 10)*(1 << (cnt++)), x /= 10;return sum;}int cal(int a, int b){int cnt = 0;while (b)    digit[++cnt] = b % 10, b /= 10;return dfs(cnt, f(a), 1);}int main(){scanf("%d", &t), memset(dp, -1, sizeof(dp));while (t--)  scanf("%d%d", &a, &b), printf("Case #%d: %d\n", cas++, cal(a, b));}IHDU 4507吉哥系列故事――恨7不成妻/*总状态转移思路(1) ans.cnt += tmp.cnt(2) ans.s += tmp.s + [ i*10^p ]*tmp.cnt(3) ans.ss += tmp.ss + 2*(i*10^p)*tmp.s + [(i*10^p)^2]*tmp.cnt(平方和公式)*/#include<iostream>#include<cstdio>#include<cstring>#include<cstring>using namespace std;typedef long long ll;const int N = 20;const int mod = 1e9 + 7;struct Node{ll cnt, s, ss;                        //与 7 无关的数的个数,与 7 无关的数的和,与 7 无关的数的平方和Node() { cnt = -1; s = 0, ss = 0; } //默认的构造函数,初始化cnt顺便标记是否访问过}dp[N + 2][10][10];ll p[N + 2], dig[N + 2];                 //保存10的次方 PS:记得取模,保存数字的每一个数位上的数void init(){p[1] = 1;                           //因为我的数字的个位用dig[1]表示,所以我用p[1]记录10的0次方for (int i = 2; i < N; ++i) p[i] = (p[i - 1] * 10) % mod;}inline ll EX(ll x)                      //求平方{x %= mod;return (x*x) % mod;}Node dfs(int len, int r1, int r2, bool up){if (len == 0){Node tmp;tmp.cnt = (r1&&r2);             //数位和不是7的倍数且数字不是7的倍数,因为这里已经完成了一组排列,只要判断这里的就行了所以&&tmp.s = tmp.ss = 0;return tmp;}if (!up&&dp[len][r1][r2].cnt != -1)return dp[len][r1][r2];int n = up ? dig[len] : 9;Node ans; ans.cnt = 0;for (int i = 0; i <= n; ++i){if (i == 7) continue;Node tmp = dfs(len - 1, (i + r1) % 7, (i + r2 * 10) % 7, up&&i == n);               //得到子状态ans.cnt = (ans.cnt + tmp.cnt) % mod;                                                //更新个数ans.s = (ans.s + (tmp.s + (i*p[len]) % mod*tmp.cnt%mod) % mod) % mod;               //更新数字ans.ss = (ans.ss + (tmp.ss + ((2LL * i*p[len] % mod)*tmp.s) % mod) % mod) % mod;    //式子太长分开写ans.ss = (ans.ss + (EX(i*p[len])*tmp.cnt) % mod) % mod;}if (!up) dp[len][r1][r2] = ans;return ans;}ll cal(ll x){int len = 0;while (x){dig[++len] = x % 10;x /= 10;}return dfs(len, 0, 0, 1).ss;}int main(){init();int T;scanf("%d", &T);while (T--){ll l, r;scanf("%lld %lld", &l, &r);printf("%lld\n", ((cal(r) - cal(l - 1)) % mod + mod) % mod);}return 0;}JSPOJ BALNUMBalanced Numbers#include <string.h>#include <stdio.h>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;LL dp[20][60000];int bit[20];bool check(int s){int num[10];for (int i = 0; i<10; i++){num[i] = s % 3;s /= 3;}for (int i = 0; i<10; i++){if (num[i] != 0){if (i % 2 == 0 && num[i] == 2)return false;//偶数数字出现了奇数次,舍去if (i % 2 == 1 && num[i] == 1)return false;//奇数数字出现了偶数次,舍去}}return true;}int getnews(int x, int s){int num[10];for (int i = 0; i<10; i++){num[i] = s % 3;s /= 3;}if (num[x] == 0)num[x] = 1;elsenum[x] = 3 - num[x];int news = 0;for (int i = 9; i >= 0; i--){news *= 3;news += num[i];}return news;}LL dfs(int pos, int s, int flag, int z){if (pos == -1)return check(s);if (!flag&&dp[pos][s] != -1)return dp[pos][s];LL ans = 0;int end = flag ? bit[pos] : 9;for (int i = 0; i <= end; i++)ans += dfs(pos - 1, (z&&i == 0) ? 0 : getnews(i, s), flag&&i == end, z&&i == 0);if (!flag)dp[pos][s] = ans;return ans;}LL solve(LL n){int len = 0;while (n){bit[len++] = n % 10;n /= 10;}return dfs(len - 1, 0, 1, 1);}int main(){int T;memset(dp, -1, sizeof(dp));LL a, b;scanf("%d", &T);while (T--){scanf("%lld%lld", &a, &b);printf("%lld\n", solve(b) - solve(a - 1));}return 0;}

原创粉丝点击