HDU 4352 XHXJ's LIS【数位DP】

时间:2022-12-16 11:59:28

题目:点击打开链接

题意:求出给定区间内有多少数的最长严格单调子序列长度等于k

分析:因为这是严格递增的,所以长度不会大于9,考虑用二进制状压保存当前情况下的LIS,令dp[pos][num][K],num表示当前情况下按位保存0~9的出现情况(num<(1<<10)),对应位置出现该数存为1,未出现则为0,若当前数为1253,则num=0000101110,考虑到用复杂度为nlogn的LIS的思想,若对于当前的数,存在非末尾的某个数位大于等于最末尾的数位,则要把num的该数位改为0,把末尾数位的数的对应数位改为1,即上例中1253中5>3,则原来值125的num=0000100110要改为0000001110而不是0000101110。若不存在非末尾的某个数位大于等于最末尾的数位,则直接把末尾数位的数的对应数位改为1。这样就保证了每次取的都是最小的值,再统计num中有多少个1,也就能求出最长的长度了。注意排除前缀零的影响。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = 1e18;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=15;
const ll MOD=1000000007;
const double eps=1e-8;
const double pi=acos(-1.0);
using namespace std;
int dig[20],K;
ll dp[20][1<<10][11],l,r;
int getsta(int x,int s)
{
    for(int i=x;i<10;i++)
        if(s&(1<<i)) return (s^(1<<i))|(1<<x);
    return s|(1<<x);
}
int getlis(int x)
{
    int ans=0;
    while(x)
    {
        if(x&1) ans++;
        x>>=1;
    }
    return ans;
}
ll dfs(int pos,int num,int lim,int first)
{
    if(pos==0) return getlis(num)==K;
    if(!lim&&dp[pos][num][K]!=-1) return dp[pos][num][K];
    int upper=lim?dig[pos]:9;
    ll res=0;
    for(int i=0;i<=upper;i++)
    {
        if(i==0&&first) res+=dfs(pos-1,0,lim&&(i==upper),1);
        else res+=dfs(pos-1,getsta(i,num),lim&&(i==upper),0);
    }
    if(!lim) dp[pos][num][K]=res;
    return res;
}
ll calc(ll x)
{
    int len=0;
    while(x)
    {
        dig[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,1,1);
}
int main()
{
    memset(dp,-1,sizeof(dp));
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        scanf("%I64d%I64d%d",&l,&r,&K);
        printf("Case #%d: %I64d\n",cas,calc(r)-calc(l-1));
    }
}