按照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