数位dp+LIS+状态压缩-hdu-4352-XHXJ's LIS

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4352

题目意思:

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

解题思路:

数位dp+LIS+状态压缩

根据求LIS的nlogn的思想,由于k最多为10,也就是最长递增序列的长度最多为10,可以状态压缩10位,维护前面的已选的递增序列,并及时更新。

dp[i][j][k]表示后面还有i位,前面状态为k,总共需要最长递增序列为j时的总数。

代码:

更新时用两种方式实现都可以。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#define eps 1e-6
#define INF 0x3fffffff
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

ll dp[25][12][1200];
int bit[25],cnt,k;

ll dfs(int cur,int s,int flag,int num,int * a)
{
    if(!cur)
    {
        if(num==k)
        {
            dp[cur][num][s]=1;
            return 1;
        }
        return 0;
    }
    if(!flag&&dp[cur][k][s]!=-1)
        return dp[cur][k][s];
    ll res=0;
    int Max=flag?bit[cur]:9;
    int tmp[25];

    for(int i=0;i<=Max;i++)
    {
        for(int j=0;j<=num;j++) //如果用二分来写的话,要防止后面最前面数组的改动
            tmp[j]=a[j];
        if(!s&&!i) //注意前置零,不能记为一个数字
        {
            res+=dfs(cur-1,0,0,0,tmp);
            continue;
        }         //但当首位不为0时,0又是一个有效的数字
        if(i>tmp[num]) //找到一个
        {
            tmp[num+1]=i;
            res+=dfs(cur-1,s|(1<<i),flag&&(i==Max),num+1,tmp);
        }
        else
        {   //找到第一个大于等于的
            int t=lower_bound(tmp,tmp+num+1,i)-tmp;
            int tt=tmp[t];
            tmp[t]=i;
            res+=dfs(cur-1,s-(1<<tt)+(1<<i),flag&&(i==Max),num,tmp);
        } //第二种实现方式,比较直观,而且复杂度稍微低点
/*        if((1<<i)>s)
            res+=dfs(cur-1,s|(1<<i),flag&&(i==Max),num+1);
        else if((1<<i)&s)
            res+=dfs(cur-1,s,flag&&(i==Max),num);
        else
        {
            for(int j=i+1;j<=9;j++)
            {
                if((1<<j)&s)
                {
                    res+=dfs(cur-1,(s-(1<<j))|(1<<i),flag&&(i==Max),num);
                    break;
                }
            }
        }*/
    }
    if(!flag)
        dp[cur][k][s]=res;
    return res;
}

ll init(ll a)
{
    cnt=0;
    while(a)
    {
        bit[++cnt]=a%10;
        a/=10;
    }
    int aa[25];
    aa[0]=-1;
    return dfs(cnt,0,1,0,aa);
}

int main()
{
    memset(dp,-1,sizeof(dp));
    int t;
    ll a,b;

    scanf("%d",&t);
    for(int ca=1;ca<=t;ca++)
    {
        scanf("%I64d%I64d%d",&a,&b,&k);
        //printf("%I64d %I64d\n",init(a,k),init(b,k));
        printf("Case #%d: %I64d\n",ca,init(b)-init(a-1));
    }
   return 0;
}





你可能感兴趣的:(动态规划)