bzoj 3209 bzoj1799 数位dp

 

3209: 花神的数论题

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 2267  Solved: 1040
[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

// 数位dp模板题 10^15最多52个1,枚举1的个数来统计就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod=1e7+7;
int bit[60],maxv;
ll dp[60][60];
ll pow_mod(ll a,ll b)
{
    if(b==0) return 1;
    ll x=pow_mod(a,b/2);
    ll ans=x*x%mod;
    if(b&1) ans=ans*a%mod;
    return ans;
}
ll dfs(int pos,int x,int limt)
{
    if(pos<=0) return x==maxv;
    if(!limt&&dp[pos][x]!=-1) return dp[pos][x];
    ll ans=0;
    int maxb=(limt?bit[pos]:1);
    for(int i=0;i<=maxb;i++){
        ans+=dfs(pos-1,x+i,limt&&(i==maxb));
    }
    if(!limt) dp[pos][x]=ans;
    return ans;
}
void solve(ll n)
{
    int nu=0;
    while(n){
        bit[++nu]=(n&1);
        n>>=1;
    }
    ll ans=1;
    for(int i=1;i<=nu;i++){
        memset(dp,-1,sizeof(dp));
        maxv=i;
        ll tmp=dfs(nu,0,1);
        ans=ans*pow_mod(i,tmp)%mod;
    }
    printf("%lld\n",ans);
}
int main()
{
    ll n;
    scanf("%lld",&n);
    solve(n);
    return 0;
}

1799: [Ahoi2009]self 同类分布

Time Limit: 50 Sec  Memory Limit: 64 MB
Submit: 1245  Solved: 535
[Submit][Status][Discuss]

Description

给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。

Input

 

Output

 

Sample Input

10 19

Sample Output

3

HINT

【约束条件】1 ≤ a ≤ b ≤ 10^18

代码:
//数位dp模板题 10^18的数数位和最大是153,然后枚举数位和然后就行了。刚开始还傻到想要求前153个数的lcm。。。。
//dfs时记录余数pre 和数位和sum。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll dp[20][200][200],po[20];
int bit[20];
ll dfs(int pos,int mod,int sum,int pre,bool w){
    if(pos<=0) return pre==0&&sum==mod;
    if(!w&&dp[pos][sum][pre]!=-1) return dp[pos][sum][pre];
    ll ans=0;
    int maxb=(w?bit[pos]:9);
    for(int i=0;i<=maxb;i++){
        ans+=dfs(pos-1,mod,sum+i,(pre+i*po[pos])%mod,w&&(i==maxb));
    }
    if(!w) dp[pos][sum][pre]=ans;
    return ans;
}
ll solve(ll x)
{
    int nu=0;
    while(x){
        bit[++nu]=x%10;
        x/=10;
    }
    ll ans=0;
    for(int mod=1;mod<=nu*9;mod++){
        memset(dp,-1,sizeof(dp));
        ans+=dfs(nu,mod,0,0,1);
    }
    return ans;
}
int main()
{
    po[1]=1;
    for(int i=2;i<=18;i++) po[i]=po[i-1]*1LL*10;
    ll a,b;
    scanf("%lld%lld",&a,&b);
    printf("%lld\n",solve(b)-solve(a-1));
    return 0;
}

 

posted @ 2017-08-17 21:07  luckilzy  阅读(371)  评论(0编辑  收藏  举报