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;
}

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

原文地址:https://www.cnblogs.com/YDDDD/p/11992771.html

时间: 2024-08-01 21:35:41

HDU - 4352 - XHXJ's LIS(数位DP)的相关文章

HDU 4352 XHXJ&#39;s LIS 数位DP + 状压

由LIS的nlogn解法 可以得出最后统计数组中数的个数即为LIS的长度 这样就可以状压了 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <c

HDU 4352 XHXJ&#39;s LIS 数位dp

题目链接:点击打开链接 题意: 一个数自身的最长子序列=每一位都是一个数字然后求的LIS 问区间内有多少个数 自身的最长子序列==k 思路: 因为自身的最长子序列至多=10,且由0~9组成,所以状压10个二进制表示0~9中哪些数字已经用过 dp[i][j] 表示长度为i的数字,最长子序列中出现的数字状态j的方法数.由于询问数=K,也存下来避免重复计算. #include <cstdio> #include <algorithm> #include <cstring> #

HDU.4352.XHXJ&#39;s LIS(数位DP 状压 LIS)

题目链接 数位DP. 至于怎么求LIS,因为只有10个数,所以可以参照O(nlogn)求LIS的方法,状压记录状态. 每次加一个数和求LIS一样更新状态.最后状态中1的个数就是LIS的长度. //93MS 3004K #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define gc() getchar() typedef long long LL; c

HDU 4352 XHXJ&#39;s LIS (数位DP,状压)

题意: 前面3/4的英文都是废话.将一个正整数看成字符串,给定一个k,问区间[L,R]中严格的LIS=k的数有多少个? 思路: 实在没有想到字符0~9最多才10种,况且也符合O(nlogn)求LIS的特点,所以用状态压缩可以解决. 看到状态压缩的字眼基本就会做了,增加一维来保存当前LIS的状态.由于求LIS时的辅助数组d[i]表示长度为i的LIS最后一个元素,d数组是严格递增的,所以好好利用d数组的特性来设计状态压缩才是关键.压缩的状态0101可以表示:仅有0和2在数组d中,即d[1]=0,d[

[数位dp+状态压缩] hdu 4352 XHXJ&#39;s LIS

题意: 给x.y.k,在[x,y] 范围内最长上升子序列长度是k的数有几个 思路: 模仿 LIS nlogn的想法,这里就只有10个数,进行状压 然后直接搜就好了不用二分 然后按位dp下去就ok了! 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"al

hdu 4352 XHXJ&#39;s LIS (数位dp)

XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 755    Accepted Submission(s): 289 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then careful

HDU 4352 XHXJ&#39;s LIS

XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1423    Accepted Submission(s): 544 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then careful

HDU 4352 XHXJ&amp;#39;s LIS(数位dp&amp;amp;状态压缩)

题目链接:[kuangbin带你飞]专题十五 数位DP B - XHXJ's LIS 题意 给定区间.求出有多少个数满足最长上升子序列(将数看作字符串)的长度为k. 思路 一个数的上升子序列最大长度为10,所以每个上升子序列的状态都能够用10个二进制位来表示. 上升子序列的变化能够用LIS的方式来更新. dp[len][num][k] len为当前的位,num为当前上升子序列的状态.k表示子序列的长度. next[s][num]为记录预处理的子序列的状态变化. cnt [num]记录各个状态的最

hdu 2089 不要62 (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 思路:用变量记录吉利数,和最高位为2的吉利数还有不是吉利数的个数... code: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10][3]; //dp[i][j] ,i表示位数,j表示状态<pre name="code"