HDU-4352-数位dp,LIS

12 篇文章 0 订阅
1 篇文章 0 订阅

题目大意:求给定区间呢的数满足最长子序列长度为k;

题目解析:LIS,dp第二维表示当前的序列,第三维表示目标长度为k,dfs的时候更新序列的时候要像LIS一样找到>=i的第一位并且去掉然后加上第i位;

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
ll dp[20][1<<10][20],num[20];
int getbit(int x)
{
	int ans=0;
	while(x)
	{
		if(x&1)	ans++;
		x>>=1;
	}
	return ans;
}
int k;
int update(int x,int s)
{
	for(int i=x;i<=9;i++)
	{
		if(s&(1<<i))
		{
			return (s^(1<<i))|(1<<x); 
		}
	}
	return s|(1<<x); 
}
ll dfs(int pos,int s,bool lead,bool limit)
{
	if(pos==-1)	return getbit(s)==k;
	if(!lead&&!limit&&dp[pos][s][k]!=-1)	return dp[pos][s][k];
	int u=limit?num[pos]:9;
	ll ans=0;
	for(int i=0;i<=u;i++)
	{
		if(lead&&i==0)
			ans+=dfs(pos-1,0,true,limit&&i==u);
		else  
			ans+=dfs(pos-1,update(i,s),lead&&(i==0),limit&&(i==u));	
	}
	if(!lead&&!limit)	return dp[pos][s][k]=ans;
	return ans;
}
ll solve(ll n)
{
	int cnt=0;
	while(n)
	{
		num[cnt++]=n%10;
		n/=10;
	}
	return dfs(cnt-1,0,true,true);
}
int main()
{
	int cas,c=1;
	memset(dp,-1,sizeof(dp));
	scanf("%d",&cas);
	while(cas--)
	{
		ll a,b;
		scanf("%lld%lld%d",&a,&b,&k);
		printf("Case #%d: ",c++);
		printf("%lld\n",solve(b)-solve(a-1));
	}
	return 0;
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值