zoukankan      html  css  js  c++  java
  • HDU 4352 XHXJ's LIS

    XHXJ's LIS

    题意:求出给定区间[L,R]  (0<L<=R<263-1 and 1<=K<=10) 满足LIS(非连续严格递增子序列)为K的个数?

    思路:从dfs的角度来思考优化,题目要求的是LIS为k的数的个数,当递归到最低位时,原本是判断整个数的LIS是否是k,那这就是朴素的枚举解法了。如果我们把不在LIS中的数位屏蔽掉(这样就是为什么最后只需要计算状态中1的个数),即前一个位为4,当前位为3时,且4不是建立在3的基础上时,那么这时的4就被3屏蔽了。(注意与每次递归中state的更新对应);即4这一位直接变为0,表示这个递归 4之后可能不在LIS里面。否则(4是建立在3的基础之上,这时3就不会威胁到4的LIS的地位了~~)不变化状态;

    当现在要加入3到后面时,如果前面state中含有的数有 1 2 4 6(按照前面的说法,里面其实就是递增的即LIS,但是不说每一个数就只出现一次,即还有屏蔽的),根据 ans +=的含义,到state为1 2 4 6这个状态,只需要求出这个状态下的所有子状态和即可压入dp式子中,那么怎么将state转化呢?换成1 2 3 4,还是1 2 3 6?如果是求一般的LIS那就是前者,那这道题又为什么是后者呢?state状态更新代表的含义又是什么呢?其实只要把所有子结构的数目都求到了这个目的达到即可;变成1 2 3 6是为了后面把6除去(是建立在3的基础上的,但目前得到的长度还是包含4而不包含3),即增长LIS的;如后面有 5,那么LIS就为 1 2 3 5,而变成1 2 3 4,这时并不可以变成1 2 3 4 5,因为3是在4后面的,不是LIS.里面dfs更新状态时,考虑到了数字出现的顺序,(dp不能改变问题的属性,只是优化而已)这是很精彩的一点。仔细品味dfs里面状态的变化就能读懂;

    还有就是前导0的问题,什么时候才能加入0?0不能为首位,否则会重复计算0的个数;当前面有数字时,那就课加入0了,至于状态的改变和3取代4一样。只是为了后面增长LIS用;

    (使用的是内置函数__builtin_popcount()来计算数位1的个数)

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,n) for(int (i)= 0;i < (n);i++)
    #define MS1(a) memset(a,-1,sizeof(a))
    typedef long long ll;
    ll dp[20][1<<10][11];
    int bit[20],K;
    int newstate(int state,int v)
    {
        for(int i = v;i < 10;i++)
            if(state &(1 << i)) return (state ^ (1 << i))|(1<<v);
        return state|(1<<v);
    }
    ll dfs(int pos,int state,bool edge,bool zero)
    {
        if(pos == -1) return __builtin_popcount(state) == K;
        if(!edge && dp[pos][state][K] != -1) return dp[pos][state][K];
        int end = edge ? bit[pos]:9;
        ll ans = 0;
        for(int i = 0;i <= end;i++){
            ans += dfs(pos - 1,(zero && i == 0)?0:newstate(state,i),edge && i == end,zero && i == 0);
        }
        if(!edge) dp[pos][state][K] = ans;
        return ans;
    }
    ll calc(ll x)
    {
        int tot = 0;
        while(x){
            bit[tot++] = x%10;
            x /= 10;
        }
        return dfs(tot - 1,0,1,1);
    }
    int main()
    {
        int T,kase = 1;
        MS1(dp);
        cin>>T;
        while(T--){
            ll L,R;
            scanf("%I64d%I64d%d",&L,&R,&K);
            printf("Case #%d: %I64d
    ",kase++,calc(R) - calc(L-1));
        }
    }
    View Code
  • 相关阅读:
    吊打996,来了?!
    微软开源浏览器自动化工具Playwright for Python(附源码)
    从0到1开始建设安全测试体系
    网友爆料vivo将取消大小周,不降薪,官方证实消息属实
    认识了一个在华为任职的50岁程序员!
    漫画:什么是自动驾驶?
    中国十大杰出人物
    最难调试修复的 bug 是怎样的?
    “十年不升职多得是,四年算什么”
    appium+pytest实现APP并发测试
  • 原文地址:https://www.cnblogs.com/hxer/p/5174003.html
Copyright © 2011-2022 走看看