[HDU4352]XHXJ's LIS

[HDU4352]XHXJ's LIS

题目大意:

\(T(T\le10000)\)组询问,每次给出\(l,r,k(l\le r\le 2^{63},k\le10)\),求若将数字看成一个字符串,有多少个\([l,r]\)中的数满足LIS为\(k\)

思路:

\(f_{i,j,k}\)表示考虑前\(i\)位,LIS中数的状态为\(j\),长度为\(k\)的方案数。数位DP即可。非边界情况可以记忆化搜索。

源代码:

#include<cstdio>
#include<cctype>
#include<cstring>
typedef long long int64;
inline int64 getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int64 x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
const int D=20;
int k,dig[D];
int64 f[D][1<<10][11];
inline int upd(const int &s,const int &x) {
	for(register int i=x;i<10;i++) {
		if((s>>i)&1) return s^(1<<i)^(1<<x);
	}
	return s^(1<<x);
}
int64 dp(const int &dep,const bool &zero,const bool &lim,const int &s) {
	if(dep==0) return __builtin_popcount(s)==k;
	if(!lim&&f[dep][s][k]!=-1) return f[dep][s][k];
	int64 ret=0;
	for(register int i=0;i<=(lim?dig[dep]:9);i++) {
		ret+=dp(dep-1,zero&&(i==0),lim&&(i==dig[dep]),(zero&&(i==0))?0:upd(s,i));
	}
	if(!lim) f[dep][s][k]=ret;
	return ret;
}
inline int64 calc(int64 n) {
	for(dig[0]=0;n;n/=10) {
		dig[++dig[0]]=n%10;
	}
	return dp(dig[0],true,true,0);
}
int main() {
	const int T=getint();
	memset(f,-1,sizeof f);
	for(register int i=1;i<=T;i++) {
		const int64 l=getint(),r=getint();
		k=getint();
		printf("Case #%d: %lld\n",i,calc(r)-calc(l-1));
	}
	return 0;
}
posted @ 2018-09-30 08:47  skylee03  阅读(144)  评论(0编辑  收藏  举报