HDU4352 lis+状压+数位dp

本文介绍了一个使用动态规划(DP)算法解决特定区间内最长递增子序列(LIS)计数的问题。通过状态压缩技巧,作者实现了一个三维DP数组来高效存储和复用中间结果,有效避免了重复计算,特别适用于测试样例中存在大量重复数字的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题干很智障,意思就是问从l到r里lis为k的数有几个
首先从0到9一共十个数,那么最长不能超过10
dp数组开一个状态,位数,k这样的三维就够
状态是状态压缩的状态
你可以用状态压缩来表达lis的数组
有点取巧了,我看别人的题解都是两维,lis部分用的nlgn方法
我第一次看见tle以后直接开了第三维记录了k爆草过去了…
因为早就料到他的测试样例里肯定有重复的和k超过10的
你看他的T有一万这么大不重复就怪了
所以特判了k超过十的直接返回0
然后dp数组本身只需要初始化一次…下次k只要一样的就能用上一轮的结果
回头再写下nlgn的

T(T<=10000)0

#include<iostream>
#include<algorithm>
#include<string>
#include<memory.h>
using namespace std;
int bte[100];
long long k;
long long dp[1<<12][20][10];
long long chai(long long n)
{
    int js = 0;
    while (n)
    {
        if (n & 1)js++;
        n >>= 1;
    }
    return js;
}
long long dfs(int weishu, int biaoji, long long zhuangtai,int qd)
{
    int as = chai(zhuangtai);
    if (weishu == 0)
    {
        if (as== k)return 1;
        return 0;
    }
    if (biaoji&&dp[zhuangtai][weishu][k] != -1)return dp[zhuangtai][weishu][k];
    int bianjie = biaoji ? 9 : bte[weishu];
    long long sum = 0;
    for (int a = 0;a <= bianjie;a++)
    {
        if (a == 0&&qd==0)sum += dfs(weishu - 1, !(biaoji == 0 && a == bianjie&&bianjie == bte[weishu]), zhuangtai,qd);
        else
        {
            long long cs = 1 << (a);
            if(cs&zhuangtai)sum+= dfs(weishu - 1, !(biaoji == 0 && a == bianjie&&bianjie == bte[weishu]), zhuangtai,1);
            else
            {
                long long xjt = zhuangtai;
                xjt +=cs;
                for (int b = a+1;b <= 9;b++)
                {
                    long long cc = 1 << (b);
                    if (cc&xjt)
                    {
                        xjt -= cc;
                        break;
                    }
                }
                sum += dfs(weishu - 1, !(biaoji == 0 && a == bianjie&&bianjie == bte[weishu]), xjt,1);
            }
        }
    }
    if (biaoji)dp[zhuangtai][weishu][k] = sum;
    return sum;
}
long long jieju(long long n)
{
    if (k > 10)return 0;
    memset(bte, 0, sizeof(bte));
    if (n <= 0)return 0;
    long long q = n;
    while (q)
    {
        bte[++bte[0]] = q % 10;
        q /= 10;
    }
    return dfs(bte[0], 0, 0,0);
}
int main()
{
#define int long long
    int T;
    cin >> T;
    int u = 0;
    memset(dp, -1, sizeof(dp));
    while (T--)
    {
        int n, m;
        cin >> n >> m >> k;
        int yu = jieju(m) - jieju(n - 1);
        printf("Case #%lld: %lld\n", ++u,yu);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值