码迷,mamicode.com
首页 > 其他好文 > 详细

【数位DP】Codeforces Gym 100418J Lucky tickets

时间:2015-08-09 22:32:23      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:codeforces   dp   数位dp   

题意:

设性质P:一个数能够整除它二进制表示下的1的个数。求[1,N]中满足性质P的数的个数。N<=1019

思路:

数位DP。首先这个数最多有64位,我们可以枚举1的个数x,然后求可以整除x的数的个数。设dp[i][j][k][w]表示从最高位枚举到i位,现在已经构成的数模x余多少(这里是关键,只用考虑余数),现在已经用了k个1,w=0表示现在枚举的这个数已经小于N了,w=1表示从最高位到第i位都与N相同(数位dp计算时的方法:如果当前枚举的数小于N了,那么枚举的这一位就可以任意,如果等于N,那么枚举的这位只能枚举小于原来N这一位的数)。

转移:

    dp[i][j][k][w]+=dp[i-1][(j+1<<i)%x][k+1][neww];(如果能放1)
    dp[i][j][k][w]+=dp[i-1][j][k][neww](放0)
    w=1&&能放1&&放了0->neww=0,w=0->neww=0

代码:

         /* Author: happywu 
         *  File: j.cpp
         *  Create Date: 2015-08-07
         */
        #include<cstdio>
        #include<iostream>
        #include<cstring>
        #include<cmath>
        #include<algorithm>
        #include<queue>
        #include<vector>
        #include<cstdlib>
        #include<time.h>
        #include<map>
        #include<set>
        #include<bitset>
        using namespace std;
        typedef long long LL;
        typedef unsigned long long  ULL;
        int b[65],length,MaxBit;
        ULL n,f[65][65][65][2];
        void pre(ULL n){
            int sum=0;
            memset(b,0,sizeof(b));length=0;
            while(n){
                if(n&1){b[sum]=1;length=sum;}
                n>>=1;
                sum++;
            }
        }
        LL dfs(int x,int y,int z,int w){
            if(x==-1){
                if(y==0&&z==MaxBit)return 1;
                else return 0;
            }
            if(f[x][y][z][w]!=-1)return f[x][y][z][w];
            LL ans=0;
            int maxb = w?b[x]:1;
            for(int i=0;i<=maxb;i++){
                if(i)ans+=dfs(x-1,(int)(((ULL)y+(1ULL<<x))%MaxBit),z+1,w);
                else {
                    int flag=1;
                    if(w==1&&maxb)flag=0;
                    if(w==0)flag=0;
                    ans+=dfs(x-1,y,z,flag);
                }
            }
            f[x][y][z][w]=ans;
            return ans;
        }
        int main(int argc, char* argv[]){
            cin>>n;
            pre(n);
            LL ans=0;
            for(int i=1;i<=length+1;i++){
                memset(f,-1,sizeof(f));
                MaxBit = i;
                ans+=dfs(length,0,0,1);
            }
            cout<<ans<<endl;
            return 0;
        }

版权声明:本文为博主原创文章,未经博主允许不得转载。

【数位DP】Codeforces Gym 100418J Lucky tickets

标签:codeforces   dp   数位dp   

原文地址:http://blog.csdn.net/wu704035hai/article/details/47380753

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!