题目
设 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 ",ans); return 0; }