• [bzoj3209]花神的数论题


    来自FallDream的博客,未经允许,请勿转载,谢谢,


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

    n<=10^15

    感觉别人的题解写的非常有道理 可以数位dp+快速幂   讲讲我的乱搞吧

    二进制位数不同的分开看 发现是

    1

    12

    1223

    ....

    每一个长度的所有数字的sum其实就是前一个搬过来,再接上一个加上一的。

    然后就可以乱搞了呗 预处理每个长度之后,先1248这样的加上去,最后剩下一个不完整的段,可以根据这个规律表示成少一位的一个不完整的段加上最多一个完整的段,递归的时候记一下后移了多少位即可。

    复杂度是logn^2+logn

    然后这个膜数不是质数 真的坑

    #include<iostream>
    #include<cstdio>
    #define mod 10000007
    #define MN 50
    #define ll long long
    using namespace std;
    
    ll Ans[MN+5],s[MN+5][MN+5];
    ll n;
    
    void Add(int i,int Move=0){for(int j=1;j+Move<=MN;++j) Ans[j+Move]+=s[i][j];}
    
    void Calc(int i,ll n,int ad)
    {
        if(!n) return;
        if(n<(1LL<<(i-1))) Calc(i-1,n,ad);
        else Calc(i-1,n-(1LL<<(i-1)),ad+1),Add(i,ad);
    }
    
    inline int pow(int x,ll k)
    {
        int sum=1;
        for(;k;k>>=1,x=1LL*x*x%mod)
            if(k&1) sum=1LL*sum*x%mod;
        return sum;
    }
    
    int main()
    {
        s[1][1]=1;
        for(int i=2;i<=MN;++i)
            for(int j=1;j<=MN;++j)
                s[i][j]=s[i-1][j]+s[i-1][j-1];
        scanf("%lld",&n);if(!n) return 0*puts("0");
        for(int i=1;(1LL<<(i-1))<=n;n-=(1LL<<(i-1)),++i) Add(i);
        Calc(MN,n,0);int ans=1;
        for(int i=1;i<=MN;++i) ans=1LL*ans*pow(i,Ans[i])%mod;
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    RabbitMq 集群配置
    获取 input 单选框和多选框的值
    js 获取 通过 ”?“ 或者 ”&“ url 传过来参数值
    Java 对文件的读取操作
    java 链接jdbc
    了解EBP寄存器
    节后后遗症
    [转]web service实现原理与异步调用
    Javascript实现无刷新分页
    邮件发送
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3209.html
Copyright © 2020-2023  润新知