#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。
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).
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.
1
123 321 2
Case #1: 139
找到从l到r之间所有满足最长上升(严格的)子序列长度为k的数的个数。
看到这种和数位有关的题,很好想到数位dp,那么数位dp行不行呢?我们来试一试。
当然为了好处理,我们把l到r的个数转换成0到r减去0到l-1的个数,然后再考虑dp。
dp要定义一个存放的数组,(不然就真的是纯暴力了,可能比模拟还慢),其实就是利用某些处理的“相似”性,或者说等价性,然后通过记录减少运算次数,进而优化时间复杂度,那么如何定义数组呢,别急,先分析一下如何dp,我们先想最暴力的dp方式:直接向下dp,记录一下处理出来的数字,最后判断最长上升子序列是不是k,当然,显然这样每个数字都要判断一遍,没有任何优化。
接下来就是要考虑怎么优化了,首先,我们想一想真正影响到结果的有什么,当然,k会影响,剩余的位数会影响,还有什么会影响呢?想一想我们求最长上升子序列怎么求:找一个low数组,记录长度为下标的结尾数字的最小值,说到这里大家可能就想到了:影响的是low数组,是的,并且很显然,如果处理到还剩一个定值位数的序列,最后需要的k相同,并且处理出来的low数组也相同,那么显然,最后得到的结果是相同的。
想到这里,后面就很简单了:怎么存low数组,显然不能开一个数组(要不然判断处理有无处理过要跑一次所有处理过的数组,显然不好),我们想一想这个low数组有什么特殊性。
其实这个low数组有一个非常特殊的地方就是它单增,严格的单增,为什么呢?因为假设有lowx>=lowy并且x<y,那么我们只要从lowy转移的里面找到第x个数放在lowx里,于是有low'x<lowy<=lowx,显然假设不成立(想想low的定义),于是我们证得单调性,于是我们就可以这样记录:一个大小为十数组,如果某一个数为一那么表示low数组里有这个数,这样就会发现一个很好的性质:如果第x个为1的数在数组的第y个里就表示lowx=y-1(数字是0,1,2,3,4,5,6,7,8,9,所有-1),这个数组里有n个1就表示最长上升子序列的长度为n。于是,有什么用呢,不还是数组吗?不一样咯,这样之后数组里只有0和1于是,状态压缩就好了。
说到这里,大家应该想到了,定义Dp[len][s]表示还剩len位未dp,前面处理后low数组的状态是s的处理值,然后递归就好了(当然要伴有有数组的记录),然后就好起来了,当然因为k相同的概率很大:10000组数据k只有10个可取的值,所有再加一维记录当要求位数为k时的值,然后遇到同样的k就可以免掉再一次计算了。
还有一个小小的问题,就是边界,这里要处理两个边界:最大,最大的时候有可能有取不到的值,还有就是0,举个例子:001的0不能取,而101的0可以取所有我们还要记录前面是不是都是0,这一题就解决了。
#include
#include
#include
using namespace std;
long long Dp[][(<<)+][];
int w[];
int len;
int k;
int ws(int a){//计算1的个数
int ans=;
while(a){
ans+=(a&);
a>>=;
}
return ans;
}
int JS(int zt,int ji){//更新low
for(int i=ji;i<=;i++)
if(zt&(<<i))
return (zt^(<<i))|(<<ji);
return zt|(<<ji);
}
long long Dfs(int len,int zt,bool lim,bool li){
if(Dp[len][zt][k]!=-&&!lim)//已经处理且不在边界
return Dp[len][zt][k];
if(len==){//到最后一位了
if(ws(zt)==k)
return ;
else
return ;
}
int ma=lim?w[len]:;//注意边界
long long ans=;
for(int i=;i<=ma;i++)
ans+=Dfs(len-,(li&&(i==))?:JS(zt,i),lim&&i==ma,li&&(i==));
if(!lim)
return Dp[len][zt][k]=ans;
else
return ans;
}
long long Cl(long long a){
len=;
while(a){
len++;
w[len]=a%;//记录每一位
a/=;
}
return Dfs(len,,,);
}
int main(){
int t;
scanf("%d",&t);
long long l,r;
memset(Dp,-,sizeof(Dp));
for(int i=;i<=t;i++){
scanf("%lld%lld%d",&l,&r,&k);
printf("Case #%d: %lld\n",i,Cl(r)-Cl(l-));
}
return ;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章