數位dp回顧

在這裏插入圖片描述
不會數位dp的同學點這裏 數位dp教學

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lb long double
#define INF 0x3f3f3f3f
const int maxn = 100035;
const int mod = 1e6 + 7;
int len;
ll dp[15][2][2][12][10];
// dp[i][j][k][l][m]表示當前搜到第i位,且前導0與最高位限制狀態爲j和k, 且要統計的數字是l, 並且已經產生m個dig的答案
int a[15];
// pos代表當前搜到第幾位,lead表示有無前導0, limit表示當前位是有限制, dig表示要統計是的數字, sum表示已經產生的dig的數量
ll dfs(int pos, int lead, int limit, int dig, int sum){
    if(pos > len) return sum; // 如果搜完了所有位數則返回答案sum
    if(!limit && !lead && dp[pos][lead][limit][dig][sum] != -1) return dp[pos][lead][limit][dig][sum];
    // 只有在無前導0且當前位無限制的時候才能利用記憶化數組dp來計算答案實現剪枝
    ll res = 0;
    int ret = limit ? a[len-pos+1] : 9; // 根據當前是否有限制來決定當前位最高能選的數字
    //當且僅當當前位有限制且選的數是當前能選的數的上限時下一位會有限制
    for(int i = 0 ; i <= ret ; ++ i){
        //如果當前選的數是0且有前導0存在, 那麼下一位一定有前導0, 且這是唯一的情況
        if(!i && lead) res += dfs(pos + 1, lead, limit && i == ret, dig, sum);
        //如果當前選的數與目標數字一樣,則sum+1
        else if(i == dig) res += dfs(pos + 1, 0, limit && i == ret, dig, sum + 1);
        //剩下的情況sum不變, 繼續往下搜
        else res += dfs(pos + 1, 0, limit && i == ret, dig, sum);
    }
    //只有無限制無前導0的情況才更新dp數組;
    return (!limit && !lead) ? dp[pos][lead][limit][dig][sum] = res : res;
}
ll cal(ll x, int y){ // 將十進制上的數存下來
    len = 0;
    while(x){
        a[++len] = x % 10;
        x /= 10;
    }
    memset(dp, -1, sizeof(dp));
    return dfs(1, 1, 1, y, 0); // 從高位向低位搜
}
int main()
{
    ll l, r;
    cin >> l >> r;
    for(int i = 0 ; i <= 9 ; ++ i){
        cout << cal(r, i) - cal(max(0LL, l - 1), i) << ' ';
    }
    return 0;
}

[HDU2089]不要62

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 100035;
const int mod = 1e6 + 7;
ll l, r;
int len; int a[16];
ll dp[20][2][2][10];
ll dfs(int pos, int lead, int limit, int last){
    if(pos > len) return 1;
    if(!limit && !lead && dp[pos][lead][limit][last] != -1) return dp[pos][lead][limit][last];
    int up = limit ? a[len-pos+1] : 9;
    ll res = 0;
    for(int i = 0 ; i <= up ; ++ i){
        if(i == 4) continue;
        if(i == 2 && last == 6) continue;
        if(!i && lead) res += dfs(pos + 1, 1, limit && i == up, i);
        else res += dfs(pos + 1, 0, limit && i == up, i);
    }
    return (!limit && !lead) ? dp[pos][lead][limit][last] = res : res;
}
ll cal(ll x){
    len = 0;
    while(x){
        a[++len] = x % 10;
        x = x / 10;
    }
    memset(dp, -1, sizeof(dp));
    return dfs(1, 1, 1, 0);
}
int main()
{
    while(scanf("%lld %lld", &l, &r) && l && r){
        cout << cal(r) - cal(l - 1) << endl;
    }
    return 0;
}

P2657 [SCOI2009]windy數

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int maxn = 100035;
const int mod = 1e6 + 7;
ll l, r;
int len; int a[16];
ll dp[20][2][2][10];
ll dfs(int pos, int lead, int limit, int last){
    if(pos > len) return 1;
    if(!limit && !lead && dp[pos][lead][limit][last] != -1) return dp[pos][lead][limit][last];
    int up = limit ? a[len-pos+1] : 9;
    ll res = 0;
    for(int i = 0 ; i <= up ; ++ i){
        if(abs(i - last) < 2) continue;
        if(!i && lead) res += dfs(pos + 1, 1, limit && i == up, -10);
        else res += dfs(pos + 1, 0, limit && i == up, i);
    }
    return (!limit && !lead) ? dp[pos][lead][limit][last] = res : res;
}
ll cal(ll x){
    len = 0;
    while(x){
        a[++len] = x % 10;
        x = x / 10;
    }
    memset(dp, -1, sizeof(dp));
    return dfs(1, 1, 1, -10);
}
int main()
{
    scanf("%lld %lld", &l, &r);
    cout << cal(r) - cal(l - 1) << endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章