[数位DP+状态压缩LIS] B - XHXJ's LIS HDU - 4352

Another hobby of xhxj is yy(speculation) some magical problems to discover the special properties. For example, when she see a number, she would think whether the digits of a number are strictly increasing. If you consider the number as a string and can get a longest strictly increasing subsequence the length of which is equal to k, the power of this number is k.. It is very simple to determine a single number’s power, but is it also easy to solve this problem with the numbers within an interval? xhxj has a little tired,she want a god cattle to help her solve this problem,the problem is: Determine how many numbers have the power value k in [L,R] in O(1)time. 
For the first one to solve this problem,xhxj will upgrade 20 favorability rate。

Input

First a integer T(T<=10000),then T lines follow, every line has three positive integer L,R,K.( 
0<L<=R<2 63-1 and 1<=K<=10).

Output

For each query, print "Case #t: ans" in a line, in which t is the number of the test case starting from 1 and ans is the answer.

Sample Input

1
123 321 2

Sample Output

Case #1: 139 
#include <bits/stdc++.h>
using namespace std;

int K;
bool flag;
int ch[30];
long long dp[20][1500][10];
int lis[1500], nx[1500][10];
// LIS 最长上升子序列

int nextt(int sum, int t)
{
	int pos = -1;
	for (int i = t; i < 10; i++)
		if (sum >> i & 1)
	{
		pos = i;  // 找到第一个大于i的数
		break;
	}
	if (pos != -1) // 找不到 加上对应位的二进制(接在原序列后) 找到则修改
		sum -= (1 << pos);
	sum += (1 << t);
	return sum;
}

void init()
{
	memset(dp, -1, sizeof dp);
	
	/// 状态压缩 用二进制数代表模拟的上升序列数组 1的个数即上升序列长度
	for (int i = 0; i < 1024; i++)
	{
		lis[i] = 0;
		for (int j = 0; j < 10; j++)
			if (i >> j & 1)
			lis[i]++;
	}
	
	/// 当前i代表的序列情况下 下一个字符为j的变更情况
	for (int i = 0; i < 1024; i++)
	{ 
		for (int j = 0; j < 10; j++)
			nx[i][j] = nextt(i, j);
	}
}

long long dfs(int pos, int sum, bool lim)
{
	if (pos == 0)
		return (lis[sum] == K) ? 1 : 0;

	if (!lim && dp[pos][sum][K] != -1)
		return dp[pos][sum][K];

	long long res = 0;
	int up = lim ? ch[pos] : 9;
	for (int i = 0; i <= up; i++)
		res += dfs(pos - 1, (!sum && !i) ? 0 : nx[sum][i], lim && (i == up));
	
	if (!lim) /// K不同答案不同
		dp[pos][sum][K] = res; 
	return res;
}

long long solve(long long x)
{
	int w = 0;
	while (x)
	{
		ch[++w] = x % 10;
		x /= 10;
	}
	return dfs(w, 0, 1);
}

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	int t;
	scanf("%d", &t);
	init();
	for (int i = 1; i <= t; i++)
	{
		long long a, b;
		scanf("%lld %lld %d", &a, &b, &K);
		printf("Case #%d: %lld\n", i, solve(b) - solve(a - 1));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ummmmm/article/details/81812045
今日推荐