HDU - 4352 - XHXJ's LIS(数位DP)

链接:

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

题意:

a 到 b中一个数组成递增子序列长度等于k的数的个数

思路:

因为只有10个数,使用二进制维护一个递增序列,每次更新在注释写了。
然后正常的数位DP,
Dp(i, j, k),i是位置,j是当前的递增状态,k是长度。
考虑一下前缀0,重置状态

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int MAXN = 1e6+10;

LL F[30][1<<10][11];
int dig[30];
LL a, b;
int k;

int Upd(int x, int s)
{
    //x表示当前值,s表示递增序列
    for (int i = x;i < 10;i++)
    {
        if (s & (1<<i))
            return (s ^ (1 << i)) | (1 << x);//找到一个比当前值大的,换成较小的
    }
    return s | (1 << x);
}

int Len(int x)
{
    int cnt = 0;
    while(x)
    {
        if (x&1)
            cnt++;
        x >>= 1;
    }
    return cnt;
}

LL Dfs(int pos, int sta, bool zer, bool lim)
{
    if (pos == -1)
        return Len(sta) == k;
    if (!lim && F[pos][sta][k] != -1)
        return F[pos][sta][k];
    int up = lim ? dig[pos] : 9;
    LL cnt = 0;
    for (int i = 0;i <= up;i++)
        cnt += Dfs(pos-1, (zer && i == 0) ? 0 : Upd(i, sta), zer && (i == 0), lim && (i == up));
    if (!lim)
        F[pos][sta][k] = cnt;
    return cnt;
}

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

int main()
{
    // freopen("test.in", "r", stdin);
    memset(F, -1, sizeof(F));
    int t, cnt = 0;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%lld%lld%d", &a, &b, &k);
        printf("Case #%d: %lld\n", ++cnt, Solve(b)-Solve(a-1));
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/YDDDD/p/11992771.html
今日推荐