F - Digits Paradise in Hexadecimal(数位dp)

题意

16 16 16进制下, [ 1 , n ] [1,n] [1,n]进制位上出现 k k k种不同数的个数。

思路

显然数位 d p dp dp,此种题一般用状压维护状态,然后就裸了。

code

// Problem: F - Digits Paradise in Hexadecimal
// Contest: AtCoder - AtCoder Beginner Contest 194
// URL: https://atcoder.jp/contests/abc194/tasks/abc194_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Date: 2021-03-09 12:52:11
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
char s[N];
int a[N],n,k;
ll dp[N][17][2][2];
int c[1<<17];
int f(int x){
	return c[x];
}
ll dfs(int x,int st,bool li=true,bool lead=true){
	int mx;
	if(c[st]>k) return 0;
	if(x==n) return c[st]==k;
	ll & ans=dp[x][c[st]][li][lead];
	if(~ans) return ans;
	ans=0; 
	mx=li?a[x]:15;
	for(int i=0;i<=mx;i++)
		ans=(ans+dfs(x+1,(!i&&lead)?st:(st|1<<i),li&(i==mx),lead&(!i)))%mod;
	return ans;
}
int main(){
	for(int i=1;i<1<<17;i++) c[i]=c[i&(i-1)]+1;
	mst(dp,-1);
	scanf("%s%d",s,&k);
	n=strlen(s);
	for(int i=0;i<n;i++)
		a[i]=isdigit(s[i])?s[i]-'0':s[i]-'A'+10;
	printf("%lld\n",dfs(0,0));
	return 0;
}