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;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/88554699
今日推荐