HDU

链接:

https://vjudge.net/problem/HDU-4734

题意:

For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).

思路:

F的最大值在5000以内。
考虑每次a都是不同的,为了减少mem的时间,我们让记录他的和变成记录当前值和F(a)的差,这样就具有通用性。不用每次的mem时间。

代码:

// #include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<string.h>
#include<set>
#include<queue>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int MAXN = 1e6+10;

LL F[15][5000];
LL dig[15];
LL m[15];
LL a, b, n, tot;

LL Dfs(int pos, LL sta, bool lim)
{
    if (pos == -1)
        return (sta >= 0);
    if (sta < 0)
        return 0;
    if (!lim && F[pos][sta] != -1)
        return F[pos][sta];
    int up = lim ? dig[pos] : 9;
    LL ans = 0;
    for (int i = 0;i <= up;i++)
        ans += Dfs(pos-1, sta-i*m[pos], lim && i == up);
    if (!lim)
        F[pos][sta] = ans;
    return ans;
}

LL Solve(LL x)
{
    int p = 0;
    while(x)
    {
        dig[p++] = x%10;
        x /= 10;
    }
    return Dfs(p-1, tot, 1);
}

int main()
{
    // freopen("test.in", "r", stdin);
    m[0] = 1;
    for (int i = 1;i < 15;i++)
        m[i] = 2*m[i-1];
    memset(F, -1, sizeof(F));
    int t, cnt = 0;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%lld %lld", &a, &b);
        tot = 0;
        int p = 0;
        while(a)
        {
            tot += (a%10)*m[p++];
            a /= 10;
        }
        printf("Case #%d: %lld
", ++cnt, Solve(b));
    }

    return 0;
}
原文地址:https://www.cnblogs.com/YDDDD/p/12000197.html