E -popcount sum 3
题目链接:https://atcoder.jp/contests/abc406/tasks/abc406_e
题意:
给定n和k,求[1,n]范围内的数字二进制位1的个数恰好为k的总和
思路:
数位dp
需要记录方案数以及数字和
根据乘法原理,每个位置1对答案的贡献为 该位置的权值(2^(i-1))x后面的方案数
int n,k;
int a[70];
int len,ans;
pii dp[70][70][2];
int vis[70][70][2];
int power[70];
pii dfs(int pos,int cnt,int limit){
if(pos>len){
if(cnt==k){
return {1,0};
}else return{0,0};
}
if(vis[pos][cnt][limit]){
return dp[pos][cnt][limit];
}
vis[pos][cnt][limit]=1;
pii res;
int up=limit?a[len-pos+1]:1;
for(int d=0;d<=up;d++){
int new_cnt=cnt+(d==1);
if(new_cnt>k)continue;
pii temp=dfs(pos+1,new_cnt,limit&&(d==up));
if(temp.fi==0)continue;
int weight=power[pos];
res.fi+=temp.fi;
res.fi%=mod;
res.se+=(((d*weight)%mod)*temp.fi)%mod+temp.se%mod;
res.se%=mod;
}
dp[pos][cnt][limit]=res;
return res;
}
void part(int x){
len=0;ans=0;
memset(vis,0,sizeof vis);
memset(dp,0,sizeof dp);
while(x){
a[++len]=x&1;x>>=1;
}
for(int i=1;i<=len;i++){
power[i]=1ll<<(len-i);
}
ans=dfs(1,0,1).se;
}
void solve(){
cin>>n>>k;
part(n);
cout<<ans%mod<<endl;
}```

浙公网安备 33010602011771号