数位DP

  数位DP题会给你用数位DP的感觉。

  dp数组的维度根据题意的限制大胆开,不变的基本上是:现在是第几位、有无限制(最高为限制)、其他限制。

  做了几个套路题,一般方法就是记忆化搜索,一般从高位往低位枚举。

  来几份板子题代码找找感觉。

  

Windy 数



#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#define Bessie signed
#define Moo ~~
#define int long long
#define re register int
using namespace std;
int read() {
    int A = 0, FL = 1;
    char C;
    C = getchar();
    while(C < '0' || C > '9') FL = C=='-' ? -1 : 1 , C = getchar();
    while(C >= '0'&& C <= '9')A = (A << 3) + (A << 1) + (C ^ '0'), C = getchar();
    return A * FL;
}
#define pc_n putchar('\n')
#define pc_ putchar(' ')
inline int max(int x, int y) {return x > y ? x: y;}
inline int min(int x, int y) {return x < y ? x: y;}
const int N = 25;
int a, b;
int dp[N][N], num[N], top;
int dfs(int tt, int lst, bool ifzero, bool ifhigh) {
    if(!tt) return !ifzero;
    if(!ifzero && !ifhigh && dp[tt][lst] != -1) return dp[tt][lst];
    int mx = ifhigh ? num[tt] : 9;//最高位有没有限制
    int res = 0;
    for(re i = 0; i <= mx; ++i)
        if(ifzero || abs(i - lst) >= 2)
            res += dfs(tt - 1, i, ifzero && i==0, ifhigh && i==mx);
    if(!ifzero && !ifhigh)
        dp[tt][lst] = res;
    return res;
}
int cnt(int x) {
    memset(dp, -1, sizeof(dp));
    top = 0;
    while(x) {
        num[++top] = x % 10;
        x /= 10;
    }
    return dfs(top, 0, 1, 1);
}
Bessie main() { 
    a = read(), b = read();
    printf("%lld\n", cnt(b) - cnt(a - 1));// 差分思想, 这样只需考虑上界即可
    return 0;
}

 

花神的数论题
 

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <set>
#include <string>
#include <cstring>
#include <map>
using namespace std;
#define int long long
#define re register int
#define pc_n printf("\n")
#define pc_ printf(" ")
#define Bessie signed
int read() {
    int a = 0, fl = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') fl = c=='-' ? -1 : 1, c = getchar();
    while(c >= '0' && c <= '9') a = (a << 3) + (a << 1) + (c ^ '0'), c = getchar();
    return a * fl;
}
const int MOD = 1e7 + 7;
int n;
int qpow(int x, int y) {
    int base = 1;
    while(y) {
        if(y & 1)
            base = base * x % MOD;
        x = x * x % MOD;
        y >>= 1;
    }
    return base;
}
int f[55][55][55][2];
int cnt[55], x[55], tot;
int dfs(int tp, int tmp, int sum, int lit) {
//从高往低填, tp -> 当前填到第几位, tmp -> 填了几个一了, sum -> 目标要填几个一, lit -> 是否受限
    if(!tp) 
        return tmp == sum;
    if(f[tp][tmp][sum][lit] != -1)
        return f[tp][tmp][sum][lit];
    int maxx = lit ? x[tp] : 1;
    int res = 0;
    for(re i = 0; i <= maxx; ++i) {
        res += dfs(tp - 1, tmp + (i == 1), sum, lit && (i == maxx));            
    }
    return f[tp][tmp][sum][lit] = res;
}
int solve() {
    while(n) {
        x[++tot] = n & 1;
        n >>= 1;
    }
    for(re i = 1; i <= 52; ++i) {
        memset(f, -1, sizeof(f));
        cnt[i] = dfs(tot, 0, i, 1);
    }
    int ans = 1;
    for(re i = 1; i <= 52; ++i) {
        ans = ans * qpow(i, cnt[i]) % MOD;
    }
    return ans;
}
Bessie main() {
    n = read();
    printf("%lld\n", solve());
    return 0;
}

 

手机号码
 

#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#define Bessie signed
#define Moo ~~
#define int long long
#define re register int
using namespace std;
int read() {
    int A = 0, FL = 1;
    char C;
    C = getchar();
    while(C < '0' || C > '9') FL = C=='-' ? -1 : 1 , C = getchar();
    while(C >= '0'&& C <= '9')A = (A << 3) + (A << 1) + (C ^ '0'), C = getchar();
    return A * FL;
}
#define pc_n putchar('\n')
#define pc_ putchar(' ')
inline int max(int x, int y) {return x > y ? x: y;}
inline int min(int x, int y) {return x < y ? x: y;}
const int N = 25, MOD = 1e7 + 7;
int l, r;
int num[N];
int tp;
int dp[15][12][12][2][2][2];
int dfs(int tt, int lst, int llst, bool three, bool four, bool eight, bool ifhigh) {
    if(four && eight) return 0;
    if(!tt) return three;
    if(!ifhigh && dp[tt][lst][llst][three][four][eight] != -1)
        return dp[tt][lst][llst][three][four][eight];
    int res = 0, mx = ifhigh ? num[tt] : 9;
    for(re i = 0; i <= mx; ++i) {
        res += dfs(tt - 1, i, lst, three || (i == lst && i == llst), four || (i == 4), eight || (i == 8), ifhigh && (i == mx));
    }
    if(!ifhigh) 
        dp[tt][lst][llst][three][four][eight] = res;
    return res;
}
int cnt(int x) {
    memset(dp, -1, sizeof(dp));
    tp = 0;
    while(x) {
        num[++tp] = x % 10;
        x /= 10;
    }
    if(tp != 11) return 0;
    int ans = 0;
    for(re i = 1; i <= num[tp]; ++i) {
        ans += dfs(tp - 1, i, 0, 0, i == 4, i == 8, i == num[tp]);
    }
    return ans;
}
Bessie main() {
    l = read(), r = read();
    printf("%lld\n", cnt(r) - cnt(l - 1));
    return 0;
}
posted @ 2022-08-08 20:52  Creator_157  阅读(19)  评论(0编辑  收藏  举报