poj 3252 数位dp (数位统计)

来源:互联网 发布:用java编写一个计算器 编辑:程序博客网 时间:2024/06/05 07:14

就是统计每个数不算本身的round数,具体解法如下

前前后后做过三遍,每一次都wa了好多次.........

dp解法:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define MAX 40using namespace std;typedef int LL;LL dp[MAX][MAX];void pre ( ){    dp[1][0] = dp[0][1] = 1;    for ( int i = 0  ; i <= 35 ; i++ )        for ( int j = 0 ; j <= 35 ; j++ )            if ( i == 0 || j == 0 ) dp[i][j] = 1;            else dp[i][j] = dp[i][j-1] + dp[i-1][j];}LL calc ( LL n ){    LL res = 0;    int cnt = 1;    int temp = 0;    if ( n == 0 ) return 1;    while ( n>>temp ) temp++;    temp--;    for ( int i = temp ; i > 0 ; i -- )    {        if ((1<<(i-1))&n)        {            for ( int j = i-1; j+1>=cnt+i-1-j&&j>=0 ; j-- )                res += dp[j][i-1-j];            cnt++;         }        else cnt--;    }    for ( int i = temp-1 ; i >= 0 ; i-- )    {        int temp;        if ( i&1 ) temp = (i+1)/2;        else temp = i/2+1;        for ( int j = i ; j >= temp ; j-- )            res += dp[j][i-j];    }    return res;}int main ( ){    LL n,m;    pre();    while ( ~scanf ( "%d%d" , &n , &m ) )    {      // cout <<"calc : 2 " << calc ( 2 ) << endl;      // cout <<"calc: 12 " << calc ( 12 ) << endl;       printf ( "%d\n" , calc (m+1) - calc ( n ) );    }}

排列组合解法:

#include <iostream>    #include <cstdio>    using namespace std;    int c[40][40],b[40];                 //注意啊,数组还是要取大些好啊,更大的空间总不会出错的,谨记//    //此函数求排列组合C(n,m),即求从m件物品中取n件有多少中取法//    void C()    {     int i,j;     c[0][0]=1;     for(i=1;i<40;i++)      for(j=0;j<=i;j++)       c[i][j]=(j==0)?c[i-1][j]:c[i-1][j]+c[i-1][j-1];    }    //此函数求小于n的数中有多少round number//    int round(int n)    {     int i=n,len=0,j,zero=0;     int ans=0;     while(i)     {      b[len++]=i%2;      i>>=1;     }                             //求n二进制//     for(i=1;i<len-1;i++)          //i+1(i+1<len)位数的二进制位数,第一位必为1,故不计入//     {      for(j=i/2+1;j<=i;j++)     //j为其中0的位数//      {       ans+=c[i][j];      }     }                           //运用排列组合知识,求从i位中取j位为零有多少种并累加//     for(i=len-2;i>=0;i--)       //计算位数为len的数中有多少小于n的round number,方法见上//     {      if(b[i])      {       for(j=(len+1)/2-zero-1;j<=i;j++)       {        ans+=c[i][j];       }      }      else zero++;                 //zero记录在搜索过程中,已发现的0的个数//     }     return ans;    }    int main()    {     int a,b;     scanf("%d%d",&a,&b);     C();     printf("%d\n",round(b+1)-round(a));//此处亦有讲究,由于我们的round()所得为小于n的round number的个数,所以b+1,//     return 0;                          //此时若b为round number,亦正确//    }

排列组合另一种写法:

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>using namespace std;int a ,b ;int s1[40], s2[40];int cnt1 = 0 , cnt2 = 0 ;long long C ( long long  index , long long  bottom ){        if ( index > bottom / 2 ) index = bottom - index ;        long long  sum1 = 1 , sum2 = 1 ;        for ( long long  i = 0 ; i < index ; i ++ )            sum1 *= (long long)  ( bottom - i );        for ( long long  i = 1 ;  i <= index ; i ++ )            sum2 *= ( long long )i;        return sum1/sum2;}int c[40][40];int ans = 0;void init ( ){        scanf ("%d%d" , &a , &b );        int zero = 0 , one = 0;        while ( a )        {            s1[++cnt1] = a%2;            a /= 2;            if ( s1[cnt1] ) one++;            else zero++;        }        if ( zero >= one  ) ans++;        while ( b )        {                s2[++cnt2] = b%2;                b/= 2;        }        c[0][0] = 1;        for ( int i  = 1 ; i <= 35 ; i ++ )            for ( int j = 0 ; j <= i ; j ++ )            {                c[j][i] = C ( j , i );                //cout << c[j][i] << endl;            }}int solve ( ){        int zero = 0;        int one = 1;        int sum1 = 0;        int sum2 = 0;        for ( int i = cnt1-1 ; i > 0 ; i -- )        {            if ( s1[i] == 1 )            {                    for ( int j = i-1 ;  zero + 1 + j >= one + i -1  - j && j >=0  ; j -- )                        sum1 += c[j][i-1];                    one++;                    //if ( one - zero <= i -1  )  sum1++;                    //cout <<i << "   "<< sum1 << endl;            }            else zero++;        }     //   cout <<sum1 <<endl;        if ( zero >= one ) sum1++;      //  if ( one != 2  && s1[1] == 1 && zero + 1 >= one - 1 ) sum1--;     // cout << sum1 <<endl;        for ( int i = cnt1 -2 ; i >= 0 ; i-- )        {            int temp;            if ( i &1 )  temp = ( i +1 )/2;            else temp = i /2 + 1;            for ( int j = i ; j >= temp ; j -- )                sum1 += c[j][i];        }      //  cout << sum1 << endl;        zero = 0 , one = 1;        for ( int i = cnt2-1 ; i > 0 ; i -- )        {            if ( s2[i] == 1 )            {                  for ( int j = i-1 ;  zero + 1 + j >= one + i -1  - j  && j >= 0    ; j -- )                    sum2 += c[j][i-1];                one++;               //  if ( one - zero <= i -1  ) sum2++;            }            else zero++;        }        if (zero >=one ) sum2++;      //   if ( one == 1 ) sum2++;        for ( int i = cnt2 - 2 ; i >= 0 ; i -- )        {            int temp;            if ( i&1 ) temp = (i+1)/2;            else temp = i/2+1;            for ( int j = i ; j >= temp ; j -- )                sum2 += c[j][i];        }        //cout << sum2 << endl;        return sum2  - sum1 + ans   ;}int main ( ){    init ( );    cout << solve ( ) << endl;}


0 0
原创粉丝点击