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