BZOJ3209(luogu 4317)花神的数论题题解

题目

设 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;
}

 

posted @ 2018-05-21 19:54  buffoons  阅读(128)  评论(0编辑  收藏  举报