B - XHXJ's LIS -数位DP-nlogn-状压LIS

  • B - XHXJ's LIS

  •  HDU - 4352 
  • S^(1<<i)把第i位变为0其余的保持不变
  • 题意:给出l,r求出L-R之间的数字有哪些是最长上升序列为k的数目通过O(nlogn)的LIS因为是数字只有10个数
  • 可以状态压缩模拟LIS过程,最终统计1的个数即可(小细节这里全是真正数字所以数字状态不能由0更新而来,会导致出现前导零情况)
  •  
  • #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 1<<11
    ll dp[25][maxn][15],l,r;
    int k,a[25],t;
    int getsum(int num)
    {
        int cnt=0;
        while(num)
        {
            num&=(num-1);
            cnt++;
        }
        return cnt;
    }
    int updata (int num,int ind)
    {
        for(int i=ind; i<=9; i++)
            if(num&(1<<i))
                return (num^(1<<i))|(1<<ind);
        return num|(1<<ind);
    }
    ll dfs(int len,int num,bool limit)
    {
        if(len==0)
            return getsum(num)==k;
        if(!limit&&dp[len][num][k]>=0)
            return dp[len][num][k];
        int up=(limit?a[len]:9);
        ll ans=0;
        for(int i=0; i<=up; i++)
            ans+=dfs(len-1,num==0&&i==0?0:updata(num,i),limit&&i==up);
        if(!limit)
            dp[len][num][k]=ans;
        return ans;
    }
    ll solve(ll x)
    {
        int len=0;
        while(x)
        {
            a[++len]=x%10;
            x/=10;
        }
        return dfs(len,0,1);
    }
    int main()
    {
        scanf("%d",&t);
        memset(dp,-1,sizeof(dp));
        for(int T=1; T<=t; T++)
        {
            scanf("%lld%lld%d",&l,&r,&k);
            printf("Case #%d: %lld\n",T,solve(r)-solve(l-1));
        }
        return 0;
    }
    
  •  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值