hdu 3943 K-th Nya Number 2011多校11 数位dp

题目

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3943

题目来源:某人帖子上扒来的,2011多校题。

简要题意:求 (P,Q] 中第 Ki 个含有 X 4 Y 7的数

数据范围: T100;0X+Y20;0<PQ<2631N100;0<Ki<263

题解

属于一眼可以看出是数位dp的题目。

dp[i][j][k] 为第 i 位有j 4k 7 的方案数。

转移的时候就按照当前这位是4,7其他分情况讨论就行了。

实现

对于找不到的情况直接开始的时候特判。

找得到的话由于范围可能很大需要二分。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>

#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
LL dp[25][25][25];
int num[25];

LL dfs(int pos, bool e, int four, int seven) {
    if (pos == -1) return four==0 && seven == 0;
    if (four < 0 || seven < 0) return 0;
    if (!e && dp[pos][four][seven] != -1) return dp[pos][four][seven];
    LL ans = 0;
    int lim = e ? num[pos] : 9;
    for (int i = 0; i <= lim; i++) {
        if (i == 4) ans += dfs(pos-1, e&&lim==i, four-1, seven);
        else if (i == 7) ans += dfs(pos-1, e&&lim==i, four, seven-1);
        else ans += dfs(pos-1, e&&lim==i, four, seven);
    }
    if (!e) dp[pos][four][seven] = ans;
    return ans;
}

LL query(LL x, int four, int seven) {
    int len = 0;
    while (x) {
        num[len++] = x%10;
        x /= 10;
    }
    return dfs(len-1, true, four, seven);
}

void solve(LL l, LL r, LL k, int four, int seven) {
    k += query(l, four, seven);
    if (query(r, four, seven) < k) {
        puts("Nya!");
        return;
    }
    LL ans = ++l;
    while (l <= r) {
        LL mid = (l+r)>>1;
        if (query(mid, four, seven) >= k) {
            ans = mid;
            r = mid-1;
        } else {
            l = mid+1;
        }
    }
    printf("%I64d\n", ans);
}

int main() {
    memset(dp, -1, sizeof dp);
    int t, n, x, y, cas = 1;
    LL l, r, k;
    scanf("%d", &t);
    while (t--) {
        scanf("%I64d%I64d%d%d%d", &l, &r, &x, &y, &n);
        printf("Case #%d:\n", cas++);
        for (int i = 0; i < n; i++) {
            scanf("%I64d", &k);
            solve(l, r, k, x, y);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值