一道很好的题、
我们发现数据范围很GG
大概log n能过
然后考虑以下关于log的算法,再选几个小数据手玩一下
可以发现:
我们将k按二进制位考虑:
对于k的每一位,
如果为0,
那么每个and的两个数的二进制最后一位位一定不能均为1,
由此得出转移方程:f [ i ] [ 0 ] = f [ i - 1 ] [ 1 ] + f [ i - 1 ] [ 0 ]
f [ i ] [ 1 ] = f [ i - 1 ] [ 0 ]
两式联立: f [ i ] [ 0 ] = f [ i - 1 ] [ 0 ] + f [ i - 2 ] [ 0 ]
即: f [ i ] = f [ i - 1 ] + f [ i - 2 ],显然是斐波那契数列
所以当k的位为0时,可以用矩阵快速幂求出斐波那契数列的第n+1项,即为答案
如果为1,
那么就很不好搞,至少有一个and中的两个数的二进制最后一位均为1
所以我们可以用总方案数减去k位为0的情况的方案数
也就是 2 ^ n - f [ n + 1 ]
最后乘法原理,将ans乘起来即可
PS:我们发现2^64会爆long long
但我们考虑一下,发现 2 ^ 60 > n ( 10 ^ 18 )
所以算到2^60即可
1 #include<cstdio> 2 #include<cassert> 3 #include<cstring> 4 using namespace std; 5 #define ll long long 6 #define N 3 7 ll ans,n,k,l,p,bin[65]; 8 struct matrix{ 9 int n,m; 10 ll mat[N][N]; 11 matrix(){ 12 memset(mat,0,sizeof(mat)); 13 } 14 friend matrix operator *(matrix m1,matrix m2){ 15 assert(m1.m=m2.n); 16 matrix res; 17 res.n=m1.m; 18 res.m=m2.m; 19 for (int i=0;i<m1.n;i++) 20 for (int j=0;j<m2.m;j++) 21 for (int k=0;k<m1.m;k++) 22 res.mat[i][j]=(res.mat[i][j]+m1.mat[i][k]*m2.mat[k][j]%p)%p; 23 return res; 24 } 25 matrix quickpow(matrix x,ll y){ 26 matrix res; 27 res.m=res.n=2; 28 res.mat[0][0]=res.mat[1][1]=1; 29 while (y){ 30 if (y&1) res=res*x; 31 x=x*x; 32 y>>=1; 33 } 34 return res; 35 } 36 }; 37 ll read(){ 38 ll sum=0; 39 char ch=getchar(); 40 while (ch<'0'||ch>'9') ch=getchar(); 41 while (ch>='0'&&ch<='9'){ 42 sum=sum*10+ch-'0'; 43 ch=getchar(); 44 } 45 return sum; 46 } 47 ll qpow(ll x,ll y){ 48 ll sum=1; 49 while (y){ 50 if (y&1) sum=sum*x%p; 51 x=x*x%p; 52 y>>=1; 53 } 54 return sum; 55 } 56 ll min(ll x,ll y){ 57 return x<y?x:y; 58 } 59 int main(){ 60 n=read(); 61 k=read(); 62 l=read(); 63 p=read(); 64 bin[0]=1;ans=1; 65 for (int i=1;i<64;i++) 66 bin[i]=bin[i-1]<<1; 67 if(k>=bin[min(60ll,l)]){ 68 printf("0"); 69 return 0; 70 } 71 matrix m0; 72 m0.n=m0.m=2; 73 m0.mat[0][1]=m0.mat[0][0]=m0.mat[1][0]=1; 74 ll maxl=qpow(2,n),t; 75 t=m0.quickpow(m0,n+1).mat[0][0]; 76 for (int i=0;i<l;i++){ 77 if (k&bin[i]&&i<=60) 78 ans=ans*(maxl-t+p)%p; 79 else ans=ans*t%p; 80 } 81 printf("%I64d",ans%p); 82 return 0; 83 }