Codeforces Round #307 (Div. 2) D. GukiZ and Binary Operations
得到k二进制后,对每一位可取得的方法进行相乘即可,k的二进制形式每一位又分为2种0,1,0时,a数组必定要为一长为n的01串,且串中不出现连续的11,1时与前述情况是相反的。
且0时其方法总数为f(n) = f(n-1) + f(n-2),其中f(2) = 3,f(1) = 3。
#include <bits/stdc++.h> using namespace std; #define ll long long ll n,k; int l,m; unsigned long long p[65]; queue<int> q; //0: f[n] = f[n-2] + f[n-1] //1: 2^i - f[n] struct matrix{ ll a[2][2]; matrix(){ a[0][0] = a[0][1] = a[1][0] = a[1][1] = 0; } void unit(){ a[0][0] = a[1][1] = 1; } matrix operator * (const matrix& p){ matrix ans; for(int i = 0;i < 2;++i){ for(int j = 0;j < 2;++j){ for(int k = 0;k < 2;++k){ ans.a[i][j] += a[i][k] * p.a[k][j]; if(ans.a[i][j] >= m) ans.a[i][j] %= m; } } } return ans; } }; ll fi(){ //f[1] = 2,f[2] = 3; if(n == 1) return 2; if(n == 2) return 3; ll t = n; t -= 2; matrix ans,p; p.a[0][0] = 1,p.a[1][0] = 1,p.a[0][1] = 1; ans.unit(); while(t){ if(t & 1) ans = ans * p; p = p * p; t >>= 1; } return (3 * ans.a[0][0] + 2 * ans.a[1][0])%m; } ll quickpow(ll x,ll y){ ll ans = 1; while(y){ if(y & 1){ ans = ans * x; if(ans >= m) ans %= m; } x *= x; if(x >= m) x %= m; y >>= 1; } return ans; } void solve(){ if(p[l] - 1 < (unsigned long long)k && l != 64){ puts("0"); return; } while(k){ q.push(k&1); k>>=1; } ll x = fi(),y = (quickpow(2,n) - x + m) % m,ans = 1; for(int i = 0;i < l;++i){ if(!q.empty()){ if(q.front()) ans = ans * y; else ans = ans * x; q.pop(); } else{ ans = ans * x; } if(ans >= m) ans %= m; } printf("%I64d\n",ans%m); } int main() { cin >> n >> k >> l >> m; p[0] = 1; for(int i = 1;i < 64;++i) p[i] = p[i-1]*2; solve(); return 0; }