数位dp

数位dp

总结一下规律
数位dp的题面大多是对数进行了一些限制,然后让你求这种数的个数。

解题有如下步骤:
1.根据题目的要求,初始化符合要求的数,用数组存下。
2.获取,题目一般会给你一个范围,考虑前缀和的思想
例如[x,y],可以转换为[1,y+1)-[1,x)
注意你的获取函数大多都是左开右闭的
3.首先位数不足的先统计
再从高到低位进行比较,假设这一位比原来数的这一位少1,设这一位为i,那你后面就可以随便取了,所以贡献就是 10^(i-1)
最后把当前情况的数量乘以贡献求和就是答案
一道稍微难一点的例题
花神的数论题

#include<bits/stdc++.h>
typedef long long ll;
const int mod=10000007;
using namespace std;
ll f[100][100],n; 
ll cnt=0,input[100];
ll qpow(ll x,ll y){
  	ll ans=1;
    while(y){
        if(y&1) ans=(ans*x)%mod;
 		x=(x*x)%mod;
        y>>=1;
    }
    return ans;
}

void init(){
    for(int i=0;i<=60;i++){//log(1e15)
        f[i][0]=1;
    }
    for(int i=1;i<=60;i++){
        for(int j=1;j<=i;j++){
            f[i][j]=f[i-1][j-1]+f[i-1][j];
        }
    }
}


void cal(){//计算n的二进制位数
  //  ll m=n+1;
    while(n){
        input[++cnt]=n&1;
        n>>=1;
    }
}

ll get(ll x){//统计二进制分解下有j个1的数,其贡献和为j^sum 
    ll sum=0;
    for(int i=cnt;i>0;i--)//首->尾 
    {
        if(input[i]) sum+=f[i-1][x--];//如果这一位为1,考虑在这一位放1,在它的后面放x-1个就够了 
        if(x<0) break;
    }
    return sum;
}
ll ans=1;
int main(){
    cin>>n;
    n++;
    cal();
    init();
//	cout<<cnt<<endl; 
    for(int i=1;i<=cnt;i++){
        ans=(ans*qpow(i,get(i))%mod)%mod;
    }
    cout<<ans<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值