HDU - 4352 XHXJ's LIS 数位dp 二进制存状态 LIS

题目链接:点击查看

题意:l - r  中有多少  最长上升序列为k的个数  不要求连续

题解:因为这个k并不大,所以我们可以想到用二进制来储存,我们再求一般的最长上升子序列时,是先保存在一个数组中,遇到一个数在替换数组中大于等于他的第一个数,如果没有,就直接加到后面,最后的数组长度即为最长上升子序列的长度,通过这个题来用二进制解决,0-9 我们用二进制的每一位来储存,遇到一个数x,在判断x-9有没有出现,是替换还是插入,剩下的就是数位dp的模板了,dp[len] [st] [k] 表示长度为len,当前状态为st,最长上升子序列为k的数目

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll dp[20][(1<<10)+10][12];
int wei[20];

int k;
int get_1(int x)
{
	int cnt=0;
	while(x)
	{
		if(x&1) cnt++;
		x/=2;
	}
	return cnt;
}
int Change(int st,int x)
{
	for(int i=x;i<=9;i++)
		if((1<<i) & st)
			return ((1<<i) ^ st) | (1<<x);
	return st | (1<<x);
}
ll dfs(int pos,int st,int head0,int limit)
{
	if(pos<0)
	{
		return get_1(st)==k;
	}
	if(!limit&&dp[pos][st][k]!=-1) return dp[pos][st][k];
	int now=limit?wei[pos]:9;
	ll ans=0;
	for(int i=0;i<=now;i++)
	{
		if(i==0&&head0)
		{
			ans+=dfs(pos-1,st,head0,limit&&i==now);
		} 
		else
		{
			ans+=dfs(pos-1,Change(st,i),0,limit&&i==now);
		}
	}
	return limit==0? dp[pos][st][k]=ans:ans;
}
ll solve(ll x)
{
	int len=0;
	while(x)
	{
		wei[len++]=x%10;
		x/=10;
	}
	return dfs(len-1,0,1,1);
}
int main()
{
	int T;
	int nn=1;
	ll l,r;
	memset(dp,-1,sizeof(dp));
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%d",&l,&r,&k);
		printf("Case #%d: %lld\n",nn++,solve(r)-solve(l-1));
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值