HDU ~ 4352 ~ XHXJ's LIS (数位DP + LIS + 状压)

题意

[L,R]区间内,各位数字组成的LIS(严格上升)长度为K的个数?

 

思路

如果还按照记忆化搜索的方式来写,那么我们过程中需要维护的是选了一个数字之后LIS的变化,我们应该怎么维护呢?

大家应该知道LIS的nlogn的求解方法。不会自行查找学习。

我们用dp数组的一维来表示我们选的这些数字的 LIS 情况,每当新加来一个数字时,我们就把他替换到第一个能替换的数字位置(LIS的更新方法),最后我们查一下状态数字有多少个1,LIS就是多长。

深搜过程中用一个变量allzero维护一下前导0的情况。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL L, R, K, dp[20][1<<10][15];
string num;
int update(int x, int state)
{
    for (int i = x; i <= 9; i++)
        if (state&(1<<i)) return (state^(1<<i))|(1<<x);
    return state|(1<<x);
}
LL dfs(int pos, int state, bool limit, bool allzero)
{
    if (pos == -1) return __builtin_popcount(state) == K;
    if (!limit && dp[pos][state][K] != -1) return dp[pos][state][K];
    LL ans = 0;
    int E = limit?num[pos]-'0':9;
    for (int i = 0; i <= E; i++)
        ans += dfs(pos-1, (allzero&&(i==0)) ? 0 : update(i, state), limit&&(i==E), allzero&&(i==0));
    if (!limit) dp[pos][state][K] = ans;
    return ans;
}
LL solve(LL x)
{
    num = to_string(x); reverse(num.begin(), num.end());
    return dfs(num.size()-1, 0, 1, 1);
}
int main()
{
    memset(dp, -1, sizeof(dp));
    int T, CASE = 1; scanf("%d", &T);
    while (T--)
    {
        scanf("%lld%lld%lld", &L, &R, &K);
        printf("Case #%d: %lld\n", CASE++, solve(R)-solve(L-1));
    }
    return 0;
}
/*
1
123 321 2
*/



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值