题意:
设性质P:一个数能够整除它二进制表示下的1的个数。求[1,N]中满足性质P的数的个数。N<=1019。
思路:
数位DP。首先这个数最多有64位,我们可以枚举1的个数x,然后求可以整除x的数的个数。设dp[i][j][k][w]表示从最高位枚举到i位,现在已经构成的数模x余多少(这里是关键,只用考虑余数),现在已经用了k个1,w=0表示现在枚举的这个数已经小于N了,w=1表示从最高位到第i位都与N相同(数位dp计算时的方法:如果当前枚举的数小于N了,那么枚举的这一位就可以任意,如果等于N,那么枚举的这位只能枚举小于原来N这一位的数)。
转移:
dp[i][j][k][w]+=dp[i-1][(j+1<<i)%x][k+1][neww];(如果能放1)
dp[i][j][k][w]+=dp[i-1][j][k][neww](放0)
w=1&&能放1&&放了0->neww=0,w=0->neww=0
代码:
/* Author: happywu
* File: j.cpp
* Create Date: 2015-08-07
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstdlib>
#include<time.h>
#include<map>
#include<set>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
int b[65],length,MaxBit;
ULL n,f[65][65][65][2];
void pre(ULL n){
int sum=0;
memset(b,0,sizeof(b));length=0;
while(n){
if(n&1){b[sum]=1;length=sum;}
n>>=1;
sum++;
}
}
LL dfs(int x,int y,int z,int w){
if(x==-1){
if(y==0&&z==MaxBit)return 1;
else return 0;
}
if(f[x][y][z][w]!=-1)return f[x][y][z][w];
LL ans=0;
int maxb = w?b[x]:1;
for(int i=0;i<=maxb;i++){
if(i)ans+=dfs(x-1,(int)(((ULL)y+(1ULL<<x))%MaxBit),z+1,w);
else {
int flag=1;
if(w==1&&maxb)flag=0;
if(w==0)flag=0;
ans+=dfs(x-1,y,z,flag);
}
}
f[x][y][z][w]=ans;
return ans;
}
int main(int argc, char* argv[]){
cin>>n;
pre(n);
LL ans=0;
for(int i=1;i<=length+1;i++){
memset(f,-1,sizeof(f));
MaxBit = i;
ans+=dfs(length,0,0,1);
}
cout<<ans<<endl;
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-03 03:58:41