• hdu4352(数位DP + LIS(nlogn))


    题目描述: 

    给定一个区间中,将区间的每一个数看成一个字符串,求这个区间内每个字符串的最大上升

    子序列等于k的个数。

    可以采用nlognLIS(用一个C数组记录长度为i的最大上升子序列的结尾最小值)

    所以可以采用dfs暴力枚举每一个数,并且由于数的长度最大为18位,

    所以c数组可以用一个状态数表示。

    dp[len][state][k],代表长度为len的数,c数组状态为state,上升子序列长度等于k的个数。

    为什么要加k这一维?因为如果有多组询问,k不相同,那么就不能用之前计算过的dp[len][state]状态,

    它保存的其实是,上升子序列长度等于之前k的个数。

    可以记忆化的理由:分析到如果不同数的前缀对C数组产生的一样,那么两者等价,那么可以记忆化。

    个人理解:其实数位DP考虑记忆化,就要从不同前缀对之后len位的影响考虑。

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define LL  long long
    LL dp[30][1<<10][15];  //长度为30,最大上升子序列状态为s,是否有等于k的个数
    int digit[100];
    int K;
    int bit(int state)
    {
        int cnt=0;
        while(state>0)
        {
            if(state & 1 ==1)
                cnt++;
            state>>=1;
        }
        return cnt;
    }
    
    int solve(int state,int i)
    {
        int j;
        int ok=0;
        for(j=i;j<=9;j++)
        {
            if(state & (1<<j))
            {
                ok=1;  break;
            }
        }
        int s;
        if(ok==1)
          s=( state ^ (1<<j) )| (1<<i);
        else
          s=state | (1<< i);
        return s;
    }
    
    LL dfs(int len,int state,bool z,bool fp)
    {
        if(  len==0  )
            return  bit(state)==K;
        if(!fp && dp[len][state][K] != -1)
             return dp[len][state][K];
        LL ret = 0 ;
        int  fpmax = fp ? digit[len] : 9;
        for(int i=0;i<=fpmax;i++)
        {
            int s=solve(state,i);
            ret += dfs(len-1,(z&&(i==0)) ? 0 : s, z&&(i==0) ,fp && i == fpmax);
        }
        if(!fp)
            dp[len][state][K] = ret;
        return ret;
    }
    
    LL f(LL n)
    {
        int len = 0;
        while(n)
        {
            digit[++len] = n % 10;
            n /= 10;
        }
        return dfs(len,0,1,true);
    }
    
    int main()
    {
       //freopen("test.txt","r",stdin);
        LL a,b;
        int t,Case=0;
         scanf("%d",&t);
         memset(dp,-1,sizeof(dp));
         while(t--)
         {
              scanf("%lld%lld%d",&a,&b,&K);
              if(a==b)
                  printf("Case #%d: %d
    ",++Case,0);
              printf("Case #%d: %lld
    ",++Case,f(b)-f(a-1));
         }
    
        return 0;
    }
  • 相关阅读:
    Redis系列(八)--缓存穿透、雪崩、更新策略
    Vue在单独引入js文件中使用ElementUI的组件
    解读浮动闭合最佳方案:clearfix
    JS replace()方法替换变量(可以对变量进行全文替换)
    Django media的设置
    使用EventBus实现兄弟组件之间的通信
    component: resolve => require(['../pages/home.vue'], resolve)
    vue中使用localStorage存储信息
    使用vue-router beforEach实现判断用户登录跳转路由筛选功能
    ES6使用常量做为函数名
  • 原文地址:https://www.cnblogs.com/xianbin7/p/4833466.html
Copyright © 2020-2023  润新知