GukiZ and Binary Operations
分類:
matrices
combinatorics
math
number theory
1.題意概述
- 給你一個長度爲n的數組
a[1...n] ,滿足a[i]<2n ,並且有(a1 and a2) or (a2 and a3) or...or (an−1 and an)=k ,答案取膜m
2.解題思路
- 考慮它的二進制位,獨立計算每個位,假設
dp[i]
表示長度爲i的序列爲0的種數,那麼容易得到遞推式爲dp[i]=dp[i−1]+dp[i−2] ,這就類似於斐波那契數列,因爲是單組用例,我們可以考慮直接map存然後去遞推,當然最正統的做法是考慮用矩陣快速冪加速地去遞推:
[dp[i]dp[i−1]]=[1110]×[dp[i−1]dp[i−2]]
3.AC代碼
ll mod;
map<ll, ll> F;
ll quickmod(ll a, ll b, ll m) {
ll ans = 1;
while(b) { //用一個循環從右到左便利b的所有二進制位
if(b & 1) { //判斷此時b[i]的二進制位是否爲1
ans = (ans * a) % m; //乘到結果上,這裏a是a^(2^i)%m
b--;//把該爲變0
}
b /= 2;
a = a * a % m;
}
return ans;
}
ll Fib(ll n) {
if(F.count(n))
return F[n];
ll k = n / 2;
if(n % 2 == 0)
return F[n] = (Fib(k) * Fib(k) % mod + Fib(k - 1) * Fib(k - 1) % mod) % mod;
return F[n] = (Fib(k) * Fib(k + 1) % mod + Fib(k - 1) * Fib(k) % mod) % mod;
}
int main() {
ll n, k, l;
scanf("%I64d%I64d%I64d%I64d", &n, &k, &l, &mod);
if(mod == 1 || k >= (1ULL << min(l, 63ll)) ) {
puts("0");
} else {
F[0] = 1, F[1] = 1;
ll res = 1;
ll zero = Fib(n + 1);
ll all = quickmod(2, n, mod);
ll temp = (all - zero + mod) % mod;
rep(i, 0, l) {
if(k & 1)
res = res * temp % mod;
else res = res * zero % mod;
k >>= 1;
}
// printf("%I64d\n", all);
printf("%I64d\n", res);
}
return 0;
}