HDU 5787 K-wolf Number(数位DP)

101 篇文章 0 订阅
8 篇文章 0 订阅

题目链接:点击打开链接

思路:

我们用dp[cur][a][b][c][d][p]表示当前到了第cur位,前四位分别是abcd并且当前是否已经小于给定的数的方案数。  我们分别算出L和R的dp值,  以及L是否符合要求, 做差并把多减的加上即可。  比赛时写的比较恶心, 不是很美观但是很直观。

细节参见代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 11;
int n, m, v,cnt= 0, sum[maxn];
ll L, R, B[33], C[33], dp[19][maxn][maxn][maxn][maxn][2], vis[19][maxn][maxn][maxn][maxn][2];
int k, kase = 0, q, id;
ll dp1(int cur, int a, int b, int c, int d, int p) {
    ll& ans = dp[cur][a][b][c][d][p];
    if(cur == cnt) return 1LL;
    if(vis[cur][a][b][c][d][p] == kase) return ans;
    vis[cur][a][b][c][d][p] = kase;
    ans = 0;
    if(p) {
        for(int i = 0; i < 10; i++) {
            if(k == 2) {
                if(d == i) continue;
            }
            else if(k == 3) {
                if(c == i || d == i) continue;
            }
            else if(k == 4) {
                if(b == i || c == i || d == i) continue;
            }
            else {
                if(a == i || b == i || c == i || d == i) continue;
            }
            if(i == 0) {
                if(d == 10) ans += dp1(cur+1, a, b, c, d, p);
                else ans += dp1(cur+1, b, c, d, i, p);
            }
            else ans += dp1(cur+1, b, c, d, i, p);
        }
    }
    else {
        for(int i = 0; i < 10; i++) {
            if(k == 2) {
                if(d == i) continue;
            }
            else if(k == 3) {
                if(c == i || d == i) continue;
            }
            else if(k == 4) {
                if(b == i || c == i || d == i) continue;
            }
            else {
                if(a == i || b == i || c == i || d == i) continue;
            }
            if(i < B[cur]) {
                if(i == 0) {
                    if(d == 10) ans += dp1(cur+1, a, b, c,d, 1);
                    else ans += dp1(cur+1, b, c,d, i, 1);
                }
                else ans += dp1(cur+1, b, c,d, i, 1);
            }
            else if(i == B[cur]) {
                if(i == 0) {
                    if(d == 10) ans += dp1(cur + 1, a, b, c, d, p);
                    else ans += dp1(cur+1, b, c, d, i, p);
                }
                else ans += dp1(cur+1, b, c, d, i, p);
            }
        }
    }
    return ans;
}
bool ok() {
    for(int i = 0; i < cnt; i++) {
        for(int j = i-1; j >= max(0, i-(k-1)); j--) {
            if(B[j] == B[i]) return false;
        }
    }
    return true;
}
int main() {
    while(~scanf("%I64d%I64d%d", &L, &R, &k)) {
        ++kase;
        ll cur = R;
        int cc = 0; cnt = 0;
        while(cur) {
            C[cc++] = cur % 10;
            cur /= 10;
        }
        for(int i = cc-1; i >= 0; i--) {
            B[cnt++] = C[i];
        }
        ll ans1 = dp1(0, 10, 10, 10, 10, 0);
        cc = 0; cnt = 0;
        cur = L;
        while(cur) {
            C[cc++] = cur % 10;
            cur /= 10;
        }
        for(int i = cc-1; i >= 0; i--) B[cnt++] = C[i];
        ++kase;
        ll ans2 = dp1(0, 10, 10, 10, 10, 0);
        if(ok()) printf("%I64d\n", ans1 - ans2 + 1);
        else printf("%I64d\n", ans1 - ans2);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值