题目
设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你 派(Sum(i)),也就是 sum(1)—sum(N) 的乘积(n<=1e15)。
分析
好吧,一看数据范围及可知暴力不可做我是不会说我打了一次暴力得了50分的,看一下让求的,恶心,仔细观察后觉得是一道数位DP,可先将n换做二进制,在每一位每一位的分析,若为0则跳过,若为1则处理一番,在处理时可先脚动模拟一番,发现和杨辉三角略有联系,故先处理处杨辉三角,最终出答案(代码里都有体现),时间是:luogu 0ms,bzoj 48ms 从中体现出了bzoj评测机运算速度较慢。
上代码
#include<bits/stdc++.h>
using namespace std;
long long al[60],bl[60],f[60][60],x[60],y[60],m=0,a,b,k=1,n,mod=10000007,ans=1,qaq[60][60];
long long power(long long a,long long b){ //快速幂
if(b==0)
return 1;
if(b==1)
return a;
return b%2==0?power(a*a%mod,b/2)%mod:a*power(a*a%mod,b/2)%mod;
}
int main(){
memset(al,0,sizeof(al));
memset(f,0,sizeof(f));
memset(bl,0,sizeof(bl));
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(qaq,0,sizeof(qaq));
for(int i=1;i<=60;i++)
f[i][1]=f[i][i]=1;
for(int i=2;i<=60;i++)
for(int j=2;j<i;j++)
f[i][j]=f[i-1][j-1]+f[i-1][j];
for(int i=1;i<=60;i++)
for(int j=1;j<=i;j++)
qaq[i][j]=qaq[i-1][j]+f[i][j];
for(int i=1;i<=60;i++)
qaq[i][1]++;
scanf("%lld",&b);
qaq[0][1]=1;
if(b%2==1)
al[1]=1;
while(b>1){
b/=2;
k++;
if(b%2==1)
al[k]=1;
}
for(int i=k;i>0;i--)
if(al[i]){
long long anss=1;
for(int j=1;j<=i;j++){
anss=anss*power(j+m,qaq[i-1][j])%mod;
}
ans=ans*anss%mod;
m++;
}
printf("%lld\n",ans);
return 0;
}