bzoj 3209: 花神的数论题(数位DP+快速幂)
2018-03-10 15:37
330 查看
传送门
http://www.lydsy.com/JudgeOnline/problem.php?id=3209Solution
如果N=2x−1,明显答案就是Πxi=1iCix。现在N取任何数,我们不能直接用组合数学的公式,没事,我们用数位DP来推。设f[i][0/1][j]表示从高位开始第i位,有/无高位限制,取了j个1的方案数。一开始有f[0][1][0]=1,其他全为0。直接推一遍得出长度为N时每个j的答案,然后用快速幂乘起来就行了。
这题我犯了一个很愚蠢的错误,我将f数组取模了,然而指数是不能先取模的!于是只在最后取模,将f数组改成long long,就通过了。
Code
#include <cstdio> #include <iostream> #include <cmath> #include <cstdlib> #include <cstring> #include <algorithm> #define maxn 105 #define MOD 10000007 using namespace std; long long num; int n, a[maxn], ans; long long f[maxn][2][maxn]; int Pow(int x, long long y){ int res = 1; while(y){ if(y & 1LL) res = 1LL * res * x % MOD; x = 1LL * x * x % MOD; y >>= 1LL; } return res; } int main(){ scanf("%lld", &num); while(num){ a[++n] = num & 1LL; num >>= 1LL; } for(int i = 1; i <= (n>>1); i++) swap(a[i], a[n-i+1]); f[0][1][0] = 1LL; for(int i = 0; i < n; i++) for(int lim = 0; lim < 2; lim++){ int up = lim ? a[i+1] : 1; for(int j = 0; j < n; j++){ if(!f[i][lim][j]) continue; for(int k = 0; k <= up; k++){ int nlim = (a[i+1] == k && lim), nj = j + (k == 1); f[i+1][nlim][nj] += f[i][lim][j]; } } } ans = 1; for(int lim = 0; lim < 2; lim++) for(int j = 1; j <= n; j++) ans = 1LL * ans * Pow(j, f [lim][j]) % MOD; printf("%d\n", ans); return 0; }
相关文章推荐
- 【bzoj3209】【花神的数论题】【数位dp+快速幂】
- BZOJ 3209 花神的数论题 数位DP+数论
- 【BZOJ3209】花神的数论题 数位DP
- [数位dp] bzoj 3209 花神的数论题
- BZOJ3209:花神的数论题(数位dp)
- 【BZOJ3209】花神的数论题 数位DP(我姿势不标准,但是可能更好写)
- BZOJ 3209 花神的数论题 数位DP+数论
- BZOJ 3209: 花神的数论题 (数位dp)
- bzoj 3209 花神的数论题(数位dp)
- BZOJ3209 花神的数论题(数位dp)
- bzoj 3209: 花神的数论题【数位dp】
- [bzoj3209][花神的数论题] (数位dp+费马小定理)
- [BZOJ]3209: 花神的数论题 数位DP
- BZOJ 3209(花神的数论题-数位统计+1,被数据范围坑了)
- 数据范围BZOJ 3209(花神的数论题-数位统计+1,被数据范围坑了)
- bzoj 3209: 花神的数论题 数位dp
- [BZOJ3209]花神的数论题(数位dp)
- BZOJ_3209_花神的数论题_组合数+数位DP
- BZOJ 3209 花神的数论题 数位dp
- [数位DP] BZOJ 3209 花神的数论题