hdu4352(数位dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4352

题意:求区间L到R之间的数A满足A的的数位的最长递增序列的长度为K的数的个数。

分析:数位dp,dp[i][j][k]表示后面还有i位,此时状态为k,最长上升子序列为j时的总数(在非限制即0~9任意填的情况下)。

要真正理解LIS的本质才能解这题,state状态维护的是前面上升子序列中出现的数字(二进制状态压缩),前面设状态为167(state为001100001),假设此时i=2,维护上升序列长度为3,应该把6变为2(此时state为001000011)127,最长上升子序列长度不变,但能让后面更多的数加进来。

这题还得注意前导0的影响。

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-9
#define N 100010
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int dig[30];
LL dp[25][11][1100];
int k;//当前位,上升子序列出现的数字的状态,长度,是否上限,是否前导0
LL dfs(int pos,int state,int num,int limit,int fzore)
{
    if(!pos)
    {
        return k==num;
    }
    if(!limit&&~dp[pos][k][state])return dp[pos][k][state];
    int len=limit?dig[pos]:9;
    LL ans=0;
    for(int i=0;i<=len;i++)
    {
        if((1<<i)>state)
            ans+=dfs(pos-1,(fzore&&!i)?0:state|(1<<i),(fzore&&!i)?0:num+1,limit&&i==len,fzore&&!i);
        else if(state&(1<<i))
            ans+=dfs(pos-1,state,num,limit&&i==len,fzore&&!i);
        else
        {
            for(int j=i+1;j<=9;j++)
            if(state&(1<<j))
            {
                ans+=dfs(pos-1,state-(1<<j)|(1<<i),num,i==len&&limit,fzore&&!i);
                break;
            }
        }
    }
    if(!limit)dp[pos][k][state]=ans;
    return ans;
}
LL solve(LL x)
{
    int len=0;
    while(x)
    {
        dig[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,0,1,1);
}
int main()
{
    int T,cas=1;
    FILL(dp,-1);
    scanf("%d",&T);
    while(T--)
    {
        LL a,b;
        scanf("%I64d%I64d%d",&a,&b,&k);
        printf("Case #%d: ",cas++);
        printf("%I64d\n",solve(b)-solve(a-1));
    }
}

时间: 2024-10-11 19:00:39

hdu4352(数位dp)的相关文章

hdu4352 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): 4246    Accepted Submission(s): 1772 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then

hdu4352---XHXJ&#39;s LIS(状态压缩数位dp)

一开始我设计的状态是dp[i][j][sta],表示第i位为j,然后状态为sta,后来发现这样会导致后面的计算直接return,得不到正确答案 重新设计状态dp[i][k][sta]表示i位数,lis=k,状态为sta的个数,这里求LIS用的是O(nlogn)求法的思想 /************************************************************************* > File Name: hdu4352.cpp > Author: ALe

数位dp专题 (HDU 4352 3652 3709 4507 CodeForces 55D POJ 3252)

数位dp核心在于状态描述,因为阶段很简单. 一般都是求有多少个数,当然也有求平方的变态题. 因为比这个数小的范围定然是从左至右开始小的,那么什么样的前缀对后面子数有相同的结果? HDU 3652 题意:求能被13整除且含有13这样数的个数. 赤裸裸的两个条件,加上个pre标明下前缀,其实直接开状态也是一样的.整除这个条件可以用余数来表示.余数转移:(mod*10+i)%13 /* *********************************************** Author :bi

数位dp小记

转载自:http://blog.csdn.net/guognib/article/details/25472879 参考: http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html kuangbin :http://www.cnblogs.com/kuangbin/category/476047.html http://blog.csdn.net/cmonkey_cfj/article/details/7798809 http:/

HDU - 4352 - XHXJ&#39;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 MO

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

HDU 3555 Bomb (数位DP)

数位dp,主要用来解决统计满足某类特殊关系或有某些特点的区间内的数的个数,它是按位来进行计数统计的,可以保存子状态,速度较快.数位dp做多了后,套路基本上都差不多,关键把要保存的状态给抽象出来,保存下来. 简介: 顾名思义,所谓的数位DP就是按照数字的个,十,百,千--位数进行的DP.数位DP的题目有着非常明显的性质: 询问[l,r]的区间内,有多少的数字满足某个性质 做法根据前缀和的思想,求出[0,l-1]和[0,r]中满足性质的数的个数,然后相减即可. 算法核心: 关于数位DP,貌似写法还是

51nod1043(数位dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1043 题意:中文题诶- 思路:数位dp 我们用dp[i][j]来存储长度为2*i且一半和为j的所有情况(包括前导0的情况),为了方便我们现在只讨论其一半的和的情况,因为如果包括前导0的话其两边的情况是一样的: 我们假设再长度为i-1的数字最前面加1位数字k,0<=k<=9(这位数字加在哪里并不影响答案,因为我们在计算i-1长度的时候已经计算了所有组合情况,

数位dp

1.[hdu3709]Balanced Number 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<ctime> 8 #include<cmath> 9 #include<queue>