zoukankan      html  css  js  c++  java
  • BZOJ 3209 花神的数论题

    题目如下:

    题目描述

    背景
    众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
    描述
    话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。
    花神的题目是这样的
    设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你
    派(Sum(i)),也就是 sum(1)—sum(N) 的乘积。

    输入

    一个正整数 N。

    输出

    一个数,答案模 10000007 的值。

    样例输入

    样例输入
    3

    样例输出

    样例输出
    2

    对于 100% 的数据,N≤10^15

    看到这道题首先想到暴力,但再看数据。。。。BZOJ上的题不是几个for循环就能做出来的。我首先计算了    sum(1)~sum(100),观察了规律。发现有很多重复的数字。1~100中最大的sum只有6(即63的二进制的一的个数),这样的话,计算 π(………)就会有很多重复的数字相乘,对于很多重复数字相乘,在计算机竞赛中我们是怎么解决得呢?对,就是快速幂,这样就可以很快地计算出答案了。既然已经想到了快速幂,接下来的工作就是统计每个数字出现的次数。在这里,当然暴力也是不可取的。。。在这里我们用到了数位DP的思想。这里使用的数位DP比较简单。不妨设一个数组来表示。C[i][j]。表示 i  位长的数字,其中有 j 个一,的数字个数。这个数字是指二进制数。那么它的状态转移方程是什么呢?C[i][j]=C[i-1][j]+C[i-1][j-1].   解释其实很简单。 i  位长的数字,一定又 i-1 位的数字转移而来。而 i-1位的数字转移有两种。即在 i-1 位的数字后加0或者加1,这样就可以转移成 i 位的数字了。初始化:C[1…n][0]=1.即所有位上都填0只有一种方案,这样就可以初始化所有的情况了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long int ll;
    const int MAXN=60+5;
    const ll mod=10000007;
    ll n, Ans;
    ll C[MAXN][MAXN];
    int l,wei[MAXN];
    void pre() {
        for (int i=0;i<=60;++i)
          C[i][0]=1;
        for(int i=1;i<=60;i++)
          for(int j=1;j<=i;++j)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
    ll Solve(int x) {
        ll sum=0;
        for (int i=l;i>=1;--i) {
          if(wei[i]==1){
            sum+=C[i-1][x];
            --x;
          }
          if(x<0) break;
        }
        return sum;
    }
    ll Pow(ll a, ll b){
        ll tot=1;
        a%=mod;
        while(b){
          if(b&1){
            tot*=a;
            tot%=mod;
          }
          b>>=1;a*=a;a%=mod;
        }
        return tot;
    }
    int main()
    {
        pre();
        scanf("%lld",&n);
        ++n;//只能计算小于n的个数,所以要加1
        l=0;
        while(n){
          wei[++l]=n&1;
          n>>=1;
        }
        Ans=1ll;
        for(int i=1;i<=l;++i)
          Ans=Ans*Pow(i,Solve(i))%mod;
        printf("%lld
    ",Ans);
        return 0;
    }
  • 相关阅读:
    2019.10.31 答辩回来后;
    2019.10.22
    2019.10.21 上周总结+今天
    2019.10.20 没有人可以阻挡自己努力,男朋友也不可以。少情感,多学习;;多夸夸他肯定他
    2019.10.19 干什么? 不要纠结了于下手什么了 趁还年轻 去做吧!!
    2019.10.16 每天问自己 三遍 或者更多:我收获了什么?我收获了什么?我收获了什么???
    Java 错误:Constructor call must be the first statement in a constructor
    2019.10.14 解决讨好型人格;时间管理划分等级+设定时间上限
    2019.10.14 今天看到的业务大佬的肺腑之言
    放几张吴悠校园行
  • 原文地址:https://www.cnblogs.com/xtx1999/p/4636262.html
Copyright © 2011-2022 走看看