zoukankan      html  css  js  c++  java
  • 洛谷4317花神的数论题(数位DP)

    传送门

    本来是想刷数论题的,万万没想到的是,这道题题目是叫数论题,但其实它是道数位DP呢。

    既然sum(i) 表示 的二进制表示中1的个数,而数据范围又很大,是1e15,暴力肯定是不行的。

    但我们知道,肯定有很多数二进制的1的个数是一样的,考虑可不可以把问题转化成对于每一个k,找出二进制里有k个1的数有多少个。

    我们发现把N换为2进制的话,也不过就是50位的样子。那么最多也才50个1,那么k从 1 for到 50,每个k找一遍,把个数存一下。

    问题转化为:对于一个区间的数,找出二进制中有k个1的数有多少个----->数位dp。

    #include<bits/stdc++.h>
    #define LL long long
    #define mod 10000007
    using namespace std;
    LL read()
    {
        LL x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    int num[52];
    LL dp[52][52][52][3],f[52];//小心爆int 
    int tot=0;
    LL dfs(int pos,int cnt,int goal,int lim)
    {
        if(!pos) return cnt==goal;
        if(~dp[pos][cnt][goal][lim])return dp[pos][cnt][goal][lim];
        int maxx=lim?num[pos]:1;
        LL res=0;
        for(int i=0;i<=maxx;++i)
          res+=dfs(pos-1,cnt+(i==1),goal,lim&&(i==maxx));
        return dp[pos][cnt][goal][lim]=res;
    }
    LL quick(LL a,LL x)
    {
        LL ans=1;
        while(x)
        {
            if(x&1)ans=ans*a%mod;
            a=a*a%mod;x>>=1;
        }
        return ans;
    }
    void solve(LL x)
    {
        while(x)
        {
            num[++tot]=x&1;
            x>>=1;
        }
        for(int i=2;i<=50;++i)memset(dp,-1,sizeof(dp)),f[i]=dfs(tot,0,i,1);//记得清空,每次要求的1的个数不同 
        LL ans=1;
        for(int i=2;i<=50;++i)
          if(f[i])ans=ans*quick(i,f[i])%mod;
        printf("%lld
    ",ans);
    }
    int main()
    {
        LL n=read();
        solve(n);
    } 
    View Code
  • 相关阅读:
    MAC LAMP环境 php执行使用问题
    centos 服务器 安全设置
    Linux系统发现占用CPU达100%的进程并处理
    git 使用国内镜像 ,查看镜像更改情况
    mac安装composer
    MySql反向模糊查询
    Linux启动或重启网卡
    MAMP环境 nginx配置忽略index.php入口文件
    php 验证码生成 不保存的情况下 缩小图片质量
    KMP字符串模式匹配详解
  • 原文地址:https://www.cnblogs.com/yyys-/p/11295638.html
Copyright © 2011-2022 走看看