【数位dp】刷题集(更新中)

模板

应用范围:[l, r]中满足某种情况的数个数

ll dfs(int pos, int pre, bool limit, bool lead) {
    if (pos == -1) return 1;
    if (!limit && !lead && dp[pos][...][...] != -1) return dp[pos][...][...];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        ******//操作1
    }
    if (!limit && !lead) dp[pos][...][...] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, true, true);
}

基础例题

不要62

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
const int N = 2e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
ll n, m, a[20], dp[20][20];
ll dfs(int pos, int pre, bool limit, bool lead) {
    if (pos == -1) return 1;
    if (!limit && !lead && dp[pos][pre] != -1) return dp[pos][pre];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        if (pre == 6) {
            if (i != 2 && i != 4) ans += dfs(pos-1, i, limit && i == End, lead && i == 0);
        } else {
            if (i != 4) ans += dfs(pos-1, i, limit && i == End, lead && i == 0);
        }
    }
    if (!limit && !lead) dp[pos][pre] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, true, true);
}
void solve(){
    memset(dp, -1, sizeof dp);
    while (cin >> n >> m) {
        if (n == 0 && m == 0) break;
        printf("%lld\n", calc(m) - calc(n-1));
    }
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

windy数

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
const int N = 2e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
ll n, m, a[20], dp[20][20];
ll dfs(int pos, int pre, bool limit, bool lead) {
    if (pos == -1) return 1;
    if (!limit && !lead && dp[pos][pre] != -1) return dp[pos][pre];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        if (lead) ans += dfs(pos-1, i, limit && i == End, lead && i == 0);
        else {
            if (abs(i - pre) >= 2) ans += dfs(pos-1, i, limit && i == End, lead && i == 0);
        }
    }
    if (!limit && !lead) dp[pos][pre] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, true, true);
}
void solve() {
    memset(dp, -1, sizeof dp);
    cin >> n >> m;
    printf("%lld\n", calc(m) - calc(n - 1));
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

手机号码

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
const int N = 2e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
ll n, m, a[20], dp[20][20][20][2][2][2];
ll dfs(int pos, int pre1, int pre2, bool limit, bool lead1, bool lead2, bool eight, bool four, bool flag) {
    if (pos == -1) return flag && !(eight && four);
    if (!limit && !lead2 && !lead2 && dp[pos][pre1][pre2][eight][four][flag] != -1) return dp[pos][pre1][pre2][eight][four][flag];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        if (!lead2) {
            ans += dfs(pos-1, i, pre1, limit && i == End, lead1 && i == 0, lead1, eight || i == 8, four || i == 4, flag || (i == pre1 && i == pre2 && pre1 == pre2));
        } else {
            ans += dfs(pos-1, i, pre1, limit && i == End, lead1 && i == 0, lead1, eight || i == 8, four || i == 4, flag);
        }
    }
    if (!limit && !lead1 && !lead2) dp[pos][pre1][pre2][eight][four][flag] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, 0, true, true, true, false, false, false);
}
void solve() {
    memset(dp, -1, sizeof dp);
    cin >> n >> m;
    printf("%lld\n", calc(m) - calc(n - 1));
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

烦人的数学作业

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define fi first
#define se second
#define il inline
#define re register
const int N = 1e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int MOD = 1e9+7;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
ll a[20], dp[20][250];
ll dfs(int pos, bool lead, bool limit, ll sum) {
    if (pos == -1) return sum;
    if (!limit && !lead && dp[pos][sum] != -1) return dp[pos][sum];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        ans += dfs(pos-1, lead && i == 0, limit && i == End, sum + i);
        ans %= MOD;
    }
    if (!limit && !lead) dp[pos][sum] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, true, true, 0);
}
void solve() {
    memset(dp, -1, sizeof dp);
    int T; cin >> T; while (T--) {
        ll n, m; cin >> n >> m;
        printf("%lld\n", (calc(m) - calc(n-1) + MOD) % MOD);
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

诡异数字

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 100, M = 1e6 + 5, INF = 0x3f3f3f3f;
const int MOD = 20020219;
ll dp[20][20][20];
int a[20], lim[20];
ll dfs(int pos, int pre, int cnt, bool limit) {
    if (pos == -1) return 1;
    if (!limit && dp[pos][pre][cnt] != -1) return dp[pos][pre][cnt];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        if (i == pre) {
            if (cnt + 1 <= lim[i]) ans = (ans + dfs(pos-1, i, cnt+1, limit && (i == End))) % MOD;
        } else {
            if (1 <= lim[i]) ans = (ans + dfs(pos-1, i, 1, limit && (i == End))) % MOD;
        }
    }
    if (!limit) dp[pos][pre][cnt] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    if (x < 0) return 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, 0, true);
}
void solve() {
    int T; cin >> T; while (T--) {
        ll n, m, q; cin >> n >> m >> q;
        memset(dp, -1, sizeof dp);
        memset(lim, 0x3f, sizeof lim);
        for (int i = 1; i <= q; i++) {
            int x, y; cin >> x >> y;
            lim[x] = min(lim[x], y);
        }
        cout << (calc(m) - calc(n-1) + MOD) % MOD << endl;
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

进阶例题

萌数

存在回文数只要满足相邻两个相同或间隔一个数相同

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define fi first
#define se second
#define il inline
#define re register
const int N = 1e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int MOD = 1e9+7;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
ll a[1005], dp[1005][20][20][2];
ll dfs(int pos, bool limit, bool lead1, bool lead2, int pre1, int pre2, bool flag) {
    if (pos == -1) return flag;
    if (!limit && !lead1 && !lead2 && dp[pos][pre1][pre2][flag] != -1) return dp[pos][pre1][pre2][flag];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        if (!lead2) ans += dfs(pos-1, limit && i == End, lead1 && i == 0, lead1, i, pre1, flag || (i == pre2 || i == pre1));
        else if (!lead1) ans += dfs(pos-1, limit && i == End, lead1 && i == 0, lead1, i, pre1, flag || (i == pre1));
        else ans += dfs(pos-1, limit && i == End, lead1 && i == 0, lead1, i, pre1, flag);
        ans %= MOD;
    }
    if (!limit && !lead1 && !lead2) dp[pos][pre1][pre2][flag] = ans;
    return ans;
}
ll calc(string s) {
    for (int i = 0; i < s.size(); i++) a[i] = s[s.size() - i - 1] - '0';
    return dfs(s.size()-1, true, true, true, 0, 0, false);
}
bool judge(string s) {
    for (int i = 1; i < s.size(); i++) {
        if (s[i] == s[i-1]) return true;
        else if (i >= 2 && s[i] == s[i-2]) return true;
    }
    return false;
}
void solve() {
    memset(dp, -1, sizeof dp);
    string n, m; cin >> n >> m;
    printf("%lld\n", (calc(m) - calc(n) + judge(n) + MOD) % MOD);
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

[AHOI2009]同类分布

枚举数字和,用dig来存模上数字和之后的值,最后数字和和模数相同而且dig为0说明可以整除原数

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define fi first
#define se second
#define il inline
#define re register
const int N = 1e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int MOD = 1e9+7;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
ll a[1005], dp[20][250][250];
ll dfs(int pos, int dig, bool limit, int sum, int mod) {
    if (pos == -1) return (sum == mod && dig == 0);
    if (!limit && dp[pos][dig][sum] != -1) return dp[pos][dig][sum];
    int End = limit ? a[pos] : 9;
    ll ans = 0;
    for (int i = 0; i <= End; i++) {
        ans += dfs(pos-1, (dig * 10 + i) % mod, limit && i == End, sum + i, mod);
    }
    if (!limit) dp[pos][dig][sum] = ans;
    return ans;
}
ll calc(ll x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    ll ans = 0;
    for (int i = 1; i <= pos*9; i++) {
        memset(dp, -1, sizeof dp);
        ans += dfs(pos-1, 0, true, 0, i);
    }
    return ans;
}

void solve() {
    ll n, m; cin >> n >> m;
    printf("%lld\n", calc(m) - calc(n-1));
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

Sum-of-Log

i&j = 0可以推出i和j在二进制相同位上只有一个为1,log2(i+j)+1表示一个数二进制的最高位数,因此枚举最高位找出所有满足i&j=0的个数乘上位数即可

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define fi first
#define se second
#define il inline
#define re register
const int N = 1e5 + 10;
const int M = 5e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int MOD = 1e9+7;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
ll a[50], b[50], dp[50][2][2];
ll dfs(int pos, bool limit1, bool limit2) {
    if (pos == -1) return 1;
    if (dp[pos][limit1][limit2] != -1) return dp[pos][limit1][limit2];
    int up1 = limit1 ? a[pos] : 1, up2 = limit2 ? b[pos] : 1;
    ll ans = 0;
    for (int i = 0; i <= up1; i++) {
        for (int j = 0; j <= up2; j++) {
            if (i && j) continue;
            ans += dfs(pos-1, limit1 && i == up1, limit2 && j == up2);
            ans %= MOD;
        }
    }
    dp[pos][limit1][limit2] = ans;
    return ans;
}
ll calc(ll x, ll y) {
    memset(dp, -1, sizeof dp);
    memset(a, 0, sizeof a);
    memset(b, 0, sizeof b);
    int pos1 = 0, pos2 = 0;
    while (x) {
        a[pos1++] = x % 2;
        x /= 2;
    }
    while (y) {
        b[pos2++] = y % 2;
        y /= 2;
    }
    ll ans = 0;
    for (int i = 0; i < max(pos1, pos2); i++) {
        ll res = 0;
        if (i < pos1) res += dfs(i-1, i == pos1-1, i >= pos2);//x的i位为1,y的i位为0
        if (i < pos2) res += dfs(i-1, i >= pos1, i == pos2-1);//x的i位为0,y的i位为1
        res %= MOD;
        ans = (ans + 1ll*(i+1) * res % MOD) % MOD;
    }
    return ans;
}

void solve() {
    int T; cin >> T; while (T--) {
        ll n, m; cin >> n >> m;
        printf("%lld\n", calc(n, m));
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值