hdu4352 数位dp+状态压缩+一个tip

按照nlogn求lis的方法,把lis的状态压缩了,每次新加一个数就把它右边第一个数的位置置为0,然后把这个数加进去

一个需要注意的地方,如果前面都是0,那么状态s中代表0的位置不可以是1,因为这种情况下0不可以被算作是lis里的一位

/*
dp[i][j][k]表示后面还有i位,前面的lis状态是j,要求lis长度为k的个数 
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k,a[20],dp[20][1<<10][11];
ll update(ll x,ll s){
    for(int i=x;i<10;i++)
        if(s&(1<<i))
            return (s^(1<<i))|(1<<x);
    return s|(1<<x);
} 
ll calc(ll s){
    ll res=0;
    for(int i=0;i<=10;i++)
        if(s&(1<<i))res++;
    return res;
}
ll dfs(ll pos,ll s,ll lim,int zero){//zero=1表示前面都是0 
    if(pos<=0)return calc(s)==k;
    if(!lim && dp[pos][s][k]!=-1)return dp[pos][s][k];
    
    ll res=0,num=lim?a[pos]:9;
    for(int i=0;i<=num;i++){
        int z=zero&&(i==0);
        res+=dfs(pos-1,z?0:update(i,s),lim&&i==num,z);
    }
    if(!lim)dp[pos][s][k]=res;
    return res;
} 
ll solve(ll x){
    if(x<0)return 0;
    int len=0;
    memset(a,0,sizeof a);
    while(x){
        a[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,1,1);
}
int main(){
    int t;
    cin>>t;
    memset(dp,-1,sizeof dp);
    ll a,b;
    for(int tt=1;tt<=t;tt++){
        cin>>a>>b>>k;
        printf("Case #%d: ",tt);
        cout<<solve(b)-solve(a-1)<<endl;
    }
}
原文地址:https://www.cnblogs.com/zsben991126/p/10730077.html