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

猜你喜欢

转载自www.cnblogs.com/skylee03/p/9727499.html
今日推荐