BZOJ3209 花神的數論題 【組合數 + 按位計數】
阿新 • • 發佈:2018-02-03
spa using code 需要 cnblogs 來講 fin tdi pac
所以我們只需要求出包含特定數量1的數有多少個
那麽指數運算時就模9988440就可以了
由於9988440不是質數,可能不存在逆元,組合數用遞推式預處理出
題目
背景
眾所周知,花神多年來憑借無邊的神力狂虐各大 OJ、OI、CF、TC …… 當然也包括 CH 啦。
描述
話說花神這天又來講課了。課後照例有超級難的神題啦…… 我等蒟蒻又遭殃了。
花神的題目是這樣的
設 sum(i) 表示 i 的二進制表示中 1 的個數。給出一個正整數 N ,花神要問你
派(Sum(i)),也就是 sum(1)—sum(N) 的乘積。
輸入格式
一個正整數 N。
輸出格式
一個數,答案模 10000007 的值。
輸入樣例
3
輸出樣例
2
提示
對於樣例一,112=2;
數據範圍與約定
對於 100% 的數據,N≤10^15
題解
直接求太大,通過手算可以發現,由於乘法的交換律,我們可以把2放在一起,3放在一起,4放在一起........
就有\(ans = 1^{a1} + 2^{a2} + 3^{a3} + ....... + n^{an}\)
所以我們只需要求出包含特定數量1的數有多少個
但有一個上限N的限制,我們考慮遞歸計算
cal(u,v)表示u位【從高到低計算】及其之後放入v個1的合法方案
如果N的u位上是1,說明可以放1
如果放1,那麽往下遞歸cal(u - 1,v - 1)
如果不放,之後\(u - 1\)位無論如何放,都不會大於N,所以就有\(C_{u - 1}^{v}\)中方案
最後累計出每一個指數,統計答案
現在考慮取模
值得一提的是,,\(1000007\)不是質數,它等於\(941 * 10627\),所以我們不能用費馬小定理
而應該用更一般的形式:\(a^{\phi(p)} \equiv 1 (mod p)\),而\(\phi(10000007) = \phi(941) * \phi(10627) = 940 * 10626 = 9988440\)
那麽指數運算時就模9988440就可以了
由於9988440不是質數,可能不存在逆元,組合數用遞推式預處理出
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
using namespace std;
const int maxn = 70,maxm = 100005,INF = 1000000000,P = 10000007,M = 9988440;
LL C[maxn][maxn],N,bit[maxn],n;
void init(){
C[0][0] = 1;
for (int i = 1; i < maxn; i++){
C[i][0] = C[i][i] = 1;
for (int j = 1; j <= (i >> 1); j++)
C[i][j] = C[i][i - j] = (C[i - 1][j - 1] + C[i - 1][j]) % M;
}
}
LL qpow(LL a,LL b){
LL ans = 1;
for (; b; b >>= 1,a = a * a % P)
if (b & 1) ans = ans * a % P;
return ans % P;
}
LL cal(int u,int v){
if (!v) return 1;
if (!u || u < v) return 0;
if (!bit[u]) return cal(u - 1,v);
return (C[u - 1][v] + cal(u - 1,v - 1)) % M;
}
int main(){
init();
cin >> N;
for (n = 1; N; n++,N >>= 1)
bit[n] = N & 1;
n--;
LL ans = 1;
for (LL i = 1; i <= n; i++)
ans = ans * qpow(i,cal(n,i)) % P;
printf("%lld\n",(ans % P + P) % P);
return 0;
}
BZOJ3209 花神的數論題 【組合數 + 按位計數】