https://atcoder.jp/contests/abc194/tasks/abc194_f
太菜了又碰到不会的数位DP题了
这题的关键是我们并不用在dp数组中存下当前已经用了哪些数字
只要令dp[pos][cnt][up][lead]=dp[枚举到哪一位了][有几个不同的数字][是否顶着上界][前面是否有非零位了]
只要其中pos,up,lead,对了,那么对于不同的st有相同的cnt,他们的答案是一样的,所以具体的st并不需要存到dp里面,只需要存位数就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=2e5+10;
const int mod=1e9+7;
int n,k;
int a[maxl];
ll dp[maxl][17][2][2];
char s[maxl];
inline ll dfs(int pos,int st,bool up,bool lead)
{
int cnt=__builtin_popcount(st);
if(cnt>k) return 0;
if(pos>n) return cnt==k && lead;
ll &ret=dp[pos][cnt][up][lead];
if(ret!=-1)
return ret;
ret=0;
int r=up?a[pos]:15;
for(int i=0;i<=r;i++)
ret=(ret+dfs(pos+1,(!i&&!lead)?st:st|(1<<i),up&&(i==r),lead|i))%mod;
return ret;
}
int main()
{
scanf("%s",s+1);scanf("%d",&k);
n=strlen(s+1);
for(int i=1;i<=n;i++)
if(s[i]>='A' && s[i]<='Z')
a[i]=s[i]-'A'+10;
else
a[i]=s[i]-'0';
memset(dp,-1,sizeof(dp));
printf("%lld\n",dfs(1,0,1,0));
return 0;
}