BZOJ:3209: 花神的数论题

今天居然没参考任何资料解决了这道数位DP,事先只是搞一道数论题练练;

思路:求SUM[1]-SUM[N]的二进制的乘积mod1000000007;

       N<=10^15;BZOJ的题不会是几个简单的FOR就完结的,

   假如N的二进制是:1001001;

                    位数:1234567

 那么当第一位是0的情况:那么数就是000000-111111

                                    序列号:  123456-123456

 发现我们可以用排列组合算出二进制有1-6个1的数比如:1个1就是C[6][1],2个1就是C[6][2],......

当第一位是0:那么就看下一位为1的位置,去枚举计算,注意第一位为1后面全部为0的情况我们要考虑。

说的比较不靠谱。

比如:第一位为0;那么枚举1-6位的位置;

       当第一位为1是:可能1-6位都为0,所以前面的这个1要考虑,

可以自己画画

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
#define N 10000007
typedef long long ll;
ll c[61][61];
int b[61];
ll kuai(ll a,ll b)//快速米
{
    ll ans=1;
    while (b)
    {
        if (b&1) ans=ans*a%N;
        a=a*a%N;
        b/=2;
    }
    return ans;
}

int main()
{
    ll n;
    int t=0;
    for (int i=0;i<=61;i++)//预先计算排列组合
    c[i][0]=1;
    for (int i=1;i<=60;i++)
    for (int j=1;j<=60;j++)
    c[i][j]=(c[i-1][j]+c[i-1][j-1]);
    
    scanf("%lld",&n);
    while (n)
       {
        t++;
        if (n&1) b[t]=1;
        n/=2;
      }
     int k=0; ll ans=1;
      for (int i=t;i>=1;i--)
      if (b[i])
        {

            ans=ans*(k+1)%N;
            for (int j=1;j<=i-1;j++)
            ans=ans*kuai(j+k,c[i-1][j])%N;
            k++;
        }
    printf("%d\n",ans);
    return 0;
}
View Code

 

                                  

posted on 2014-06-25 23:38  forgot93  阅读(411)  评论(0编辑  收藏  举报

导航