HDU4352-XHXJ's LIS(LIS+状态压缩)

#define xhxj (Xin Hang senior sister(学姐))
If you do not know xhxj, then carefully reading the entire description is very important.
As the strongest fighting force in UESTC, xhxj grew up in Jintang, a border town of Chengdu.
Like many god cattles, xhxj has a legendary life:
2010.04, had not yet begun to learn the algorithm, xhxj won the second prize in the university contest. And in this fall, xhxj got one gold medal and one silver medal of regional contest. In the next year’s summer, xhxj was invited to Beijing to attend the astar onsite. A few months later, xhxj got two gold medals and was also qualified for world’s final. However, xhxj was defeated by zhymaoiing in the competition that determined who would go to the world’s final(there is only one team for every university to send to the world’s final) .Now, xhxj is much more stronger than ever,and she will go to the dreaming country to compete in TCO final.
As you see, xhxj always keeps a short hair(reasons unknown), so she looks like a boy( I will not tell you she is actually a lovely girl), wearing yellow T-shirt. When she is not talking, her round face feels very lovely, attracting others to touch her face gently。Unlike God Luo’s, another UESTC god cattle who has cool and noble charm, xhxj is quite approachable, lively, clever. On the other hand,xhxj is very sensitive to the beautiful properties, “this problem has a very good properties”,she always said that after ACing a very hard problem. She often helps in finding solutions, even though she is not good at the problems of that type.
Xhxj loves many games such as,Dota, ocg, mahjong, Starcraft 2, Diablo 3.etc,if you can beat her in any game above, you will get her admire and become a god cattle. She is very concerned with her younger schoolfellows, if she saw someone on a DOTA platform, she would say: “Why do not you go to improve your programming skill”. When she receives sincere compliments from others, she would say modestly: "Please don’t flatter at me.(Please don’t black)."As she will graduate after no more than one year, xhxj also wants to fall in love. However, the man in her dreams has not yet appeared, so she now prefers girls.
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

分析:

题意:
给出三个数字L和R(L<=R),K;如果把L到R的每个数都看做一个字符,那么这些字符串中最长递增子序列长度为K的有多少种?

解析:
对于这道题网上说要用LIS的O(nlogn)的算法和状态压缩!O(nlogn)的算法咱们不会啊!所以咱们就要先学!

(赞也不想写那么多,就网上找了解法的讲解!)
假设存在一个序列d[1…9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。n
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了

首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1

然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1

接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1…2] = 1, 5,Len=2

再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1…2] = 1, 3,Len = 2

继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1…3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。

第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1…3] = 1, 3, 4, Len继续等于3

第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了

第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。

最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1…5] = 1, 3, 4, 7, 9,Len = 5。

于是我们知道了LIS的长度为5。
注意:这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。

同时,这道题还得用到状态压缩的算法,因为这里是单个字符,所以他的值是从0~9,所以我们用十个二进制位记录整个字符串中的状态,如果一个数位的值是1,那么这个数是存在的,反之不存则为0;那么结合上面的O(nlogn)的最大递增子列的方法进行更新:

	bool flag=false;
	for(j=i;j<=9;j++)
	{
		if(x&(1<<j))
		{
			flag=true;
			break;
		}
	}
	if(flag)//flag作为标记,是否有大于等于i的数
		S=(x^(1<<j))|(1<<i);//大于等于i的数是存在的,如果存在,那么更新 
	else
		S=x|(1<<i);//如果不存在,同样更新

代码:

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

long long dp[20][1<<10][15];
int number[50]; 
long long K;

int bit(int x)
{
	int sum=0;
	while(x)
	{
		if(x&1)//记录比他小的数的个数 
			sum++;
		x>>=1;
	}
	return sum;
}

int slove(int x,int i)
{
	int S,j;
	bool flag=false;
	for(j=i;j<=9;j++)
	{
		if(x&(1<<j))
		{
			flag=true;
			break;
		}
	}
	if(flag)
		S=(x^(1<<j))|(1<<i);//大于等于i的数是存在的,那么那么更新最大递增子列 
	else
		S=x|(1<<i);
	return S;
}

long long dfs(int len,int x,bool z,bool b)//len记录当前数位,x表示当前数位前一个位置的值,b记录前一位的值是否为最大 ,z记录前面是否出现非0数 
{
	if(!len)//已经出现了len个数,如果最长递增子列的长度为K,返回1 
		return bit(x)==K;
	if(!b&&dp[len][x][K]!=-1)//这种状态已经出现过了 
        return dp[len][x][K];
    long long sum=0;
    int Max=b?number[len]:9; 
    for(int i=0;i<=Max;i++)
    {
        int s=slove(x,i);
        sum+=dfs(len-1,(z&&!i)?0:s,z&&!i,b&&(i==Max));
    }
    if(!b)
        dp[len][x][K]=sum;
    return sum;
}

long long getarray(long long x)
{
	int len=0;
	while(x)
	{
		number[++len]=x%10;
		x/=10;
	}
	return dfs(len,0,true,true);
}

int main()
{
	long long L,R;
	int T;
	scanf("%d",&T);
	memset(dp,-1,sizeof(dp));
	for(int t=1;t<=T;t++)
	{
		scanf("%lld%lld%d",&L,&R,&K);
		if(L==R)
			printf("Case #%d: 0\n",t);
		else
			printf("Case #%d: %lld\n",t,getarray(R)-getarray(L-1));
	}
	return 0;
}
发布了64 篇原创文章 · 获赞 17 · 访问量 869

猜你喜欢

转载自blog.csdn.net/weixin_43357583/article/details/105494118
今日推荐