zoukankan      html  css  js  c++  java
  • bzoj 3209: 花神的数论题 数位dp

    3209: 花神的数论题

    Time Limit: 10 Sec  Memory Limit: 128 MB
    [Submit][Status][Discuss]

    Description

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

    Input

    一个正整数 N。

    Output

    一个数,答案模 10000007 的值。

    Sample Input

    样例输入一

    3

    Sample Output

    样例输出一

    2

    HINT



    对于样例一,1*1*2=2;


    数据范围与约定


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

    Source

    原创 Memphis

    思路:现在我们将问题转化成,找1-r区间内二进制数为i的个数,这样就是简单的数位dp了,然后求出个数之后,只需要快速幂一下即可;

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<string>
    #include<queue>
    #include<algorithm>
    #include<stack>
    #include<cstring>
    #include<vector>
    #include<list>
    #include<set>
    #include<map>
    using namespace std;
    #define ll long long
    #define pi (4*atan(1.0))
    #define eps 1e-4
    #define bug(x)  cout<<"bug"<<x<<endl;
    const int N=1e5+10,M=1e6+10,inf=2147483647;
    const ll INF=1e18+10,mod=2147493647;
    ll f[60][60],bit[60];
    ll dp(int pos,int sum,int p,int flag)
    {
        if(pos==0)return (sum==p);
        if(flag&&f[pos][sum]!=-1)return f[pos][sum];
        int x=flag?1:bit[pos];
        ll ans=0;
        for(int i=0;i<=x;i++)
        {
            ans+=dp(pos-1,sum+i,p,flag||i<x);
        }
        if(flag)f[pos][sum]=ans;
        return ans;
    }
    ll getans(ll x,int p)
    {
        int len=0;
        while(x)
        {
            bit[++len]=x%2;
            x/=2;
        }
        return dp(len,0,p,0);
    }
    ll quick(ll a,ll b,ll c)
    {
        ll ans=1;
        while(b)
        {
            if(b&1)ans=(ans*a)%c;
            b>>=1;
            a=(a*a)%c;
        }
        return ans;
    }
    int main()
    {
        ll r;
        scanf("%lld",&r);
        ll ans=1;
        for(int i=1;i<=60;i++)
        {
            memset(f,-1,sizeof(f));
            //cout<<i<<" "<<getans(r,i)<<endl;
            //memset(f,-1,sizeof(f));
            ans=(ans*quick(i,getans(r,i),10000007))%10000007;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    今天,你ak了吗?①
    线段树模板
    DP(关于字符串,数字串的)
    Leedsdiscussion
    高数积分求旋转体体积
    tiny mission
    莫队+数组低级化的 优先队列
    LAB2
    Leedslecturepronouncation
    Eclipse Access Restriction
  • 原文地址:https://www.cnblogs.com/jhz033/p/6594343.html
Copyright © 2011-2022 走看看