花神的数论题(数位dp)

规定sum[i] 为i里面含1的个数 ,求从1-N sum[i]的乘积。

数为64位内的,也就是sum[i]<=64的,这样可以dp求出1-N中含k个1的数有多少个,快速幂一下就可以了。

有个地方没开LL ,WA了几次。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define LL long long
12 #define mod 10000007
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 LL dp[65][65][65];
18 int di[65];
19 LL dfs(int i,bool e,int k,int s)
20 {
21     if(i==-1) return k==s;
22     if(!e&&~dp[i][k][s]) return dp[i][k][s];
23     int mk = e?di[i]:1;
24     LL ans = 0;
25     for(int j = 0 ; j <= mk ; j++)
26     {
27         ans = ans+dfs(i-1,e&&(j==mk),k,s+j);
28     }
29     return e?ans:dp[i][k][s] = ans;
30 }
31 LL exp_mod(int a,LL n)
32 {
33     LL t;
34     if(n==0) return 1;
35     if(n==1) return a;
36     t = exp_mod(a,n/2);
37     t = (t*t)%mod;
38     if(n&1) t = (t*a)%mod;
39     return t;
40 }
41 LL cal(LL n)
42 {
43     int g=0;
44     while(n)
45     {
46         di[g++] = n%2;
47         n/=2;
48     }
49     LL ans = 1;
50     for(int i = 1 ;i <= g ; i++)
51     {
52         LL num = dfs(g-1,1,i,0);
53         ans = (ans*exp_mod(i,num))%mod;
54     }
55     return ans;
56 }
57 int main()
58 {
59     LL n;
60     memset(dp,-1,sizeof(dp));
61     while(cin>>n)
62     {
63         cout<<cal(n)<<endl;
64     }
65     return 0;
66 }
View Code
原文地址:https://www.cnblogs.com/shangyu/p/3821024.html