acwing算法提高之动态规划--数位DP

目录

  • 1 基础知识
  • 2 模板
  • 3 训练

1 基础知识

暂无。。。

2 模板

暂无。。。

3 训练

题目1:度的数量。

解题思路:分类讨论。

C++代码如下,

#include 
#include 

using namespace std;

const int N = 35;
int K, B;
int f[N][N];

void init() {
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j <= i; ++j) {
            if (!j) f[i][j] = 1;
            else f[i][j] = f[i-1][j] + f[i-1][j-1];
        }
    }
    return;
}

int dp(int n) {
    if (!n) return 0;
    
    vector<int> nums;
    while (n) nums.emplace_back(n % B), n /= B;
    
    int res = 0;
    int last = 0;
    for (int i = nums.size() - 1; i >= 0; --i) {
        int x = nums[i];
        if (x) { //求左边分支中的数的个数
            res += f[i][K - last];
            if (x > 1) {
                if (K - last - 1 >= 0) res += f[i][K - last - 1];
                break;
            } else {
                last++;
                if (last > K) break;
            }
        }
        if (!i && last == K) res++; //最右侧分支上的方案
    }
    return res;
}

int main() {
    init();
    
    int l, r;
    cin >> l >> r >> K >> B;
    
    cout << dp(r) - dp(l - 1) << endl;
    
    return 0;
}

题目2:1082数字游戏

C++代码如下,

#include 
#include 
#include 
#include 

using namespace std;

const int N = 15;

int f[N][N]; //f[i][j]表示一共有i位,且最高位填j的数的个数

void init() {
    for (int i = 0; i <= 9; ++i) f[1][i] = 1;
    
    for (int i = 2; i < N; ++i) {
        for (int j = 0; j <= 9; ++j) {
            for (int k = j; k <= 9; ++k) {
                f[i][j] += f[i - 1][k];
            }
        }
    }
}

int dp(int n) {
    if (!n) return 1;
    
    vector<int> nums;
    while (n) nums.emplace_back(n % 10), n /= 10;
    
    int res = 0;
    int last = 0;
    for (int i = nums.size() - 1; i >= 0; --i) {
        int x = nums[i];
        for (int j = last; j < x; ++j) {
            res += f[i + 1][j];
        }
        
        if (x < last) break;
        last = x;
        
        if (!i) res++;
    }
    return res;
}

int main() {
    init();
    
    int l, r;
    while (cin >> l >> r) cout << dp(r) - dp(l - 1) << endl;
    
    return 0;
}

题目3:1083Windy数

C++代码如下,

#include 
#include 
#include 
#include 

using namespace std;

const int N = 11;

int f[N][10];

void init() {
    for (int i = 0; i <= 9; ++i) f[1][i] = 1;
    
    for (int i = 2; i < N; ++i) {
        for (int j = 0; j <= 9; ++j) {
            for (int k = 0; k <= 9; ++k) {
                if (abs(j - k) >= 2) {
                    f[i][j] += f[i - 1][k];
                }
            }
        }
    }
}

int dp(int n) {
    if (!n) {
        return 0;
    }
    
    vector<int> nums;
    while (n) nums.emplace_back(n % 10), n /= 10;
    
    int res = 0;
    int last = -2;
    for (int i = nums.size() - 1; i >= 0; --i) {
        int x = nums[i];
        for (int j = i == nums.size() - 1; j < x; ++j) {
            if (abs(j - last) >= 2) {
                res += f[i + 1][j];
            }
        }
        
        if (abs(x - last) >= 2) {
            last = x;
        } else {
            break;
        }
        
        if (!i) {
            res++;
        }
    }
    
    //特殊处理有前导零的数
    for (int i = 1; i < nums.size(); ++i) {
        for (int j = 1; j <= 9; ++j) {
            res += f[i][j];
        }
    }
    
    return res;
}

int main() {
    init();
    
    int l, r;
    cin >> l >> r;
    cout << dp(r) - dp(l - 1) << endl;
    
    return 0;
}

题目4:1084数字游戏II

C++代码如下,

#include 
#include 
#include 
#include 

using namespace std;

const int N = 11, M = 110;

int P;
int f[N][10][M];

int mod(int x, int y) {
    return (x % y + y) % y;
}

void init() {
    memset(f, 0, sizeof f);
    
    for (int i = 0; i <= 9; ++i) f[1][i][i % P]++;
    
    for (int i = 2; i < N; ++i) {
        for (int j = 0; j <= 9; ++j) {
            for (int k = 0; k < P; ++k) {
                for (int x = 0; x <= 9; ++x) {
                    f[i][j][k] += f[i - 1][x][mod(k - j, P)];
                }
            }
        }
    }
}

int dp(int n) {
    if (!n) return 1;
    
    vector<int> nums;
    while (n) nums.emplace_back(n % 10), n /= 10;
    
    int res = 0;
    int last = 0;
    for (int i = nums.size() - 1; i >= 0; --i) {
        int x = nums[i];
        for (int j = 0; j < x; ++j) {
            res += f[i + 1][j][mod(-last, P)];
        }
        last += x;
        
        if (!i && last % P == 0) {
            res += 1;
        }
    }
    return res;
}

int main() {
    int l, r;
    while (cin >> l >> r >> P) {
        init();
        
        cout << dp(r) - dp(l - 1) << endl;
    }
    
    return 0;
}

题目5

你可能感兴趣的:(Acwing,C++学习,算法,动态规划)