hdu 3943 数位dp+二分

题意: 求p - q 范围内满足有x个4和y个7的第K个数。
思路: 数位dp。然后二分位置。

code

#include 
using namespace std;
typedef long long ll;
int T;
ll p, q;
int query;
int x, y;
int num[10010];
ll dp[100][100][100];
ll dfs(int i, int n4, int n7, bool e, int n1, int n2){
    if(i == -1){
        if(n4 == n1&&n7 == n2) return 1;
        return 0;
    }
    if(!e&&dp[i][n4][n7] != -1) return dp[i][n4][n7];
    int End = e?num[i]:9;
    ll res = 0;
    for(int k=0; k<=End; k++){
        if(k == 4) res += dfs(i-1, n4+1, n7, e&&k==End, n1, n2);
        else if(k == 7) res += dfs(i-1, n4, n7+1, e&&k==End, n1, n2);
        else res += dfs(i-1, n4, n7, e&&k==End, n1, n2); 
    }
    return e?res:dp[i][n4][n7] = res;
}
ll solve(ll a, int n1, int n2){
    int cnt = 0;
    while(a){
       num[cnt++] = a % 10;
       a /= 10;
    }
    return dfs(cnt-1, 0, 0, true, n1, n2);
}
int main(){
    cin>>T;
    ll tmp;
    int icase = 0;
    while(T--){
        scanf("%lld %lld %d %d", &p, &q, &x, &y);
        memset(dp, -1, sizeof(dp));
        cin>>query;
        printf("Case #%d:\n", ++icase);
        while(query--){
            scanf("%lld", &tmp);
            ll l = p+1; ll r = q;
            ll s = solve(p, x, y);
            s += tmp;
            ll ans = -1;
            while(l<=r){
                ll mid = (l + r) >> 1;
                ll tt = solve(mid, x, y);
                if(tt >= s){
                    ans = mid;
                    r = mid - 1;
                }
                else l = mid + 1;
            }
            if(ans == -1) puts("Nya!");
            else printf("%lld\n", ans);
        }
    }
    return 0;
}

你可能感兴趣的:(多校联合训练,hdu题解)