HDU 4352 XHXJ's LIS

Posted asuldb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4352 XHXJ's LIS相关的知识,希望对你有一定的参考价值。

题目

题意:定义一个数字的LIS为将其看成一个字符串的LIS,问([l,r])内有多少数字的LIS长度为(k)

考虑树状数组求一个序列LIS的过程,我们定义了一个东西(f_i)表示结尾元素不超过(i)的LIS的最大长度,维护这个数组就能实现较为快速的转移

显然这个数组是单调不降的,且不难发现(f_i-f_{i-1}leq 1),于是差分之后就只会存在(0,1)两种元素

于是我们在数位dp的过程中把差分序列记下来作为dp的状态就好了,注意前导零的问题,以及预处理转移会更快

代码

#include<cstdio>
#include<cstring>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
LL L,R;int k,m,lm[66];
int id[(1<<10)+5],st[11][(1<<10)+5],cnt[(1<<10)+5];
LL dp[2][(1<<10)+5][2];
int A[(1<<10)+5][11],tr[(1<<10)+5][11],B[11],M[11];
inline void trans(int state) {
    for(re int i=0;i<10;++i)A[m][i]=state>>i&1;
    for(re int i=1;i<10;++i)A[m][i]+=A[m][i-1]; 
}
inline void Pre_tr(int x) {
    for(re int i=0;i<10;i++) {
        for(re int j=0;j<10;j++)B[j]=A[x][j];
        B[i]=max(B[i],(i>0?A[x][i-1]:0)+1);
        for(re int j=1;j<10;j++)B[j]=max(B[j-1],B[j]);
        tr[x][i]=B[0];
        for(re int j=1;j<10;j++) tr[x][i]|=((B[j]-B[j-1])<<j);
        tr[x][i]=id[tr[x][i]];
    }
}
void dfs(int x,int state,int res) {
    if(res<0) return;
    if(x==10) {
        id[state]=++m;trans(state);
        cnt[m]=res;st[res][++M[res]]=m;
        return;
    }
    dfs(x+1,state,res);
    dfs(x+1,state|(1<<x),res+1);
}
inline LL calc(LL N) {
    if(!N)return 0;int tot=0;
    while(N) lm[++tot]=N%10ll,N/=10ll;
    int o=0;memset(dp,0,sizeof(dp));
    for(re int i=tot;i;--i,o^=1) {
        dp[o][id[0]][i==tot?1:0]++;
        for(re int j=1;j<=m;j++) dp[o^1][j][0]=dp[o^1][j][1]=0;
        for(re int j=1;j<=m;j++) {
            if(!dp[o][j][0]) continue;
            if(cnt[j]>=k) continue;
            for(re int k=0;k<10;++k)
                if(tr[j][k]) dp[o^1][tr[j][k]][0]+=dp[o][j][0];
        }
        for(re int j=1;j<=m;j++) {
            if(!dp[o][j][1]) continue;
            if(cnt[j]>=k) continue;
            for(re int k=0;k<lm[i];++k)
                if(tr[j][k]) dp[o^1][tr[j][k]][0]+=dp[o][j][1];
            if(tr[j][lm[i]]) dp[o^1][tr[j][lm[i]]][1]+=dp[o][j][1];
        }
        dp[o^1][tr[id[0]][0]][lm[i]?0:1]--;
    }
    LL ans=0;
    for(re int i=1;i<=M[k];i++) ans+=dp[o][st[k][i]][0]+dp[o][st[k][i]][1];
    return ans;
}
int main() {
    m=0;dfs(0,0,0);
    for(re int i=1;i<=m;i++) Pre_tr(i);
    int T;scanf("%d",&T);
    for(re int tnum=1;tnum<=T;++tnum) {
        scanf("%lld%lld%d",&L,&R,&k);
        printf("Case #%d: %lld
",tnum,calc(R)-calc(L-1));
    }
    return 0;
}

之后这玩意就T没了,原因是(Tleq 10^4),实在是不小;于是改成记忆化才行

#include<cstdio>
#include<cstring>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
LL L,R;int k,m,lm[66];
int id[(1<<10)+5],cnt[(1<<10)+5];
LL dp[20][(1<<10)+5][11];
int A[(1<<10)+5][11],tr[(1<<10)+5][11],B[11],M[11];
inline void trans(int state) {
    for(re int i=0;i<10;++i)A[m][i]=state>>i&1;
    for(re int i=1;i<10;++i)A[m][i]+=A[m][i-1]; 
}
inline void Pre_tr(int x) {
    for(re int i=0;i<10;i++) {
        for(re int j=0;j<10;j++)B[j]=A[x][j];
        B[i]=max(B[i],(i>0?A[x][i-1]:0)+1);
        for(re int j=1;j<10;j++)B[j]=max(B[j-1],B[j]);
        tr[x][i]=B[0];
        for(re int j=1;j<10;j++) tr[x][i]|=((B[j]-B[j-1])<<j);
        tr[x][i]=id[tr[x][i]];
    }
}
void dfs(int x,int state,int res) {
    if(res<0) return;
    if(x==10) {
        id[state]=++m;trans(state);cnt[m]=res;
        return;
    }
    dfs(x+1,state,res);
    dfs(x+1,state|(1<<x),res+1);
}
LL DFS(int len,int lim,int s) {
    if(!len||cnt[s]>k) return cnt[s]==k;
    if(!lim&&dp[len][s][k]!=-1) return dp[len][s][k];
    LL ans=0;
    for(re int i=0;i<=(lim?lm[len]:9);++i)
        ans+=DFS(len-1,lim&&(i==lm[len]),tr[s][i]);
    if(!lim) dp[len][s][k]=ans;
    return ans;
}
inline LL calc(LL N) {
    if(!N)return 0;int tot=0;
    while(N) lm[++tot]=N%10ll,N/=10ll;
    return DFS(tot,1,id[0]);
}
int main() {
    m=0;dfs(0,0,0);memset(dp,-1,sizeof(dp));
    for(re int i=1;i<=m;i++) Pre_tr(i);tr[id[0]][0]=id[0];
    int T;scanf("%d",&T);
    for(re int tnum=1;tnum<=T;++tnum) {
        scanf("%lld%lld%d",&L,&R,&k);
        printf("Case #%d: %lld
",tnum,calc(R)-calc(L-1));
    }
    return 0;
}
//g++ hdu4352.cpp -o hdu4352

以上是关于HDU 4352 XHXJ's LIS的主要内容,如果未能解决你的问题,请参考以下文章

hdu 4352 XHXJ's LIS

HDU - 4352 - XHXJ's LIS(数位DP)

HDU 4352 - XHXJ's LIS - [数位DP][LIS问题]

HDU 4352 XHXJ's LIS (数位DP+状态压缩+LIS)

hdu4352 XHXJ's LIS(数位dp)

HDU 4352 XHXJ's LIS