cf#307-D. GukiZ and Binary Operations-矩阵快速幂

来源:互联网 发布:淘宝店仓库管理制度 编辑:程序博客网 时间:2024/05/16 19:22

http://codeforces.com/contest/551/problem/D

给你 n,l,k,m;

题意:你可以任意挑选小于2^l的n个数,让它们以这个公式

计算得到k;要使得 得到的k与给出的k相等,问你有多少种方案数,答案取余m。


首先我们看如何得到k;

我们需要构造n个数

我们先把这n个数转为 L位 二进制数,得到一个0 1 矩阵:

xxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxx

同时我们也把k转为 L位 二进制数:

000000000000111111

我们可以知道,要使得k的第i位为0,则要求 n个数中,不能有相邻的两个数 的 【第i 位】都为1   (如果相邻为1,根据公式推得 k的第i位最终必为 1);

假如我们能求出,这个使ki位0的方案数,我们设有x种情况符合该条件;

并且,由于这n个数的第i位,总共最多只有2的n次方总情况。(每一个数的第i位有2种情况,n个数是2^n种情况)

同样的,如果要使得k的第i位为1,其情况有y=2^n-x种


注意:  

 1、如果这n个数的第i位确定了是111100(从上到下),他与第i-1位完全没关系,相互独立,也就是说,k的每一位我们都可以独立计算,位与位之间并没有关联。  (之前一直误以为是选n个数,如果是选的话,选了n个数使得k的第i位为0,第i-1,i-2,i-3位都会被确定下来,那就无法做下去了。但是我们是构造n个数,构造的话,每一bit之间是没影响的)


接下来是怎么计算   在n 个数 的情况下 ,经过公式计算 能得到 k的第i位为0,也就是n个数在第i位里【没有相邻的两个1】存在;

可发现,这个答案为f(n)=f(n-1)+f(n-2); 恰好是斐波那契数列,由于n太大 10^18//这个证明迟点再写

我们可以用矩阵快速幂来计算 得到 这个x

然后对k的每一位判断,如果是0,则ans*=x;

如果是1,则ans*=y;

最后输出 ans%mod;


/***************************************************************

为什么    一个n长度的零壹数组,每个位置元素随意,要求 不能存在相邻的两个1,求多少种排列,的答案是斐波那契数列?

证明: 

如果n长度的串第一位是0 ,那么后面随便跟,n-1长度的合法串方案书就是f(n-1)
如果n长度的串第一位是1,那么第二位肯定是0,后面随便跟,n-2长度的合法串方案书就是f(n-2)

第一位只有这两种情况,就是f(n)=f(n-1)+f(n-2)

****************************************************************/

#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>#include <map>#include <set>#include <vector>using namespace std;struct martix{__int64 m[2][2];}; martix unit_matrix;__int64 mod; __int64 len=2;martix mul(martix a,martix b){martix ret;__int64 i,j,k;for (i=0;i<len;i++){for (j=0;j<len;j++){ret.m[i][j]=0;for (k=0;k<len;k++){ret.m[i][j]+=a.m[i][k]*b.m[k][j]; ret.m[i][j]%=mod;}}}return ret;}martix pow_m(martix a,__int64 b){martix ret= unit_matrix;while(b){if (b&1)ret=mul(ret,a);a=mul(a,a);b>>=1;}return ret;}__int64 pow_m_int(__int64 a,__int64 b){__int64 ret= 1;while(b){if (b&1)ret=(ret*a)%mod;a=a*a%mod;b>>=1;}return ret%mod;}int main(){__int64 n,k,l;__int64 i,j;scanf("%I64d%I64d%I64d%I64d",&n,&k,&l,&mod);for(i = 0; i < 2; i++)            for(j = 0; j < 2; j++)                unit_matrix.m[i][j] = 0;for(i = 0; i < 2; i++)//初始化单位矩阵unit_matrix.m[i][i] = 1;if ( pow(2.0,l)<= k){printf("0\n");return 0;} martix x;  x.m[0][0]=1; x.m[0][1]=1;x.m[1][0]=1; x.m[1][1]=0;  x=pow_m(x,n+1); //n个数的该位有ans种情况使得k的该位为0    __int64 xx=x.m[0][0]%mod;__int64 one=(pow_m_int(2,n)-xx)%mod; if (one<0)one+=mod;__int64 sum=1;for (i=0;i<l;i++){if (k&1)sum=(sum*one)%mod;elsesum=sum*xx%mod;k>>=1;} printf("%I64d\n",sum%mod);return 0;}





0 0
原创粉丝点击