• [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;
    }
  • 相关阅读:
    mysql 数据库检查与修复的办法
    SECPATH透明模式下VLAN透传配置实例
    腾讯QQ所有的服务器
    AutoRuns 9.13 汉化版
    IP地址在数据库中的存储解决方案
    DNS智能解析 for windows 2003
    Windows Media Player ActiveX 控件参数
    删除nvidia右键菜单
    通过js控制cookies
    正确使用|(按位或)和||(逻辑或)
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj3209.html
Copyright © 2020-2023  润新知