codeforces #307 D. GukiZ and Binary Operations(各种快速幂+斐波那契)

来源:互联网 发布:linux tomcat 改端口 编辑:程序博客网 时间:2024/05/16 19:25

题目链接:

罪恶的链接

题目大意:

有一个数组,(a1&&a2)|| ....... (an-1&&an)=k,ai<=2^l,求取这样的数组的数量%m

题目分析:

作为一个弱渣,这道题调了一上午才过,简直了。。。。

其实思路很简单,首先将k化为二进制数,那么如果k的某一个二进制位是0,那么也就是这个数组的相邻数位不可能全是1

因此我们得到如下的递推式:dp[i] = dp[i-1]+dp[i-2],当第i位放0时,那么有dp[i-1]中情况,如果第i位放1,那么第i-1位必须放0,所以有dp[i-2]种情况,正好可以看出是斐波那契数列,那么我们可以通过矩阵快速幂快速求取

然后看为1的情况,dp[i] = 2^n-1 + dp[i-1] ,表示当前两个数位都是1,那么其他的随便放,也就是2^n-1,如果当前两个数位不全是1,那么前面必有一个是1,所以是dp[i-1]种,但是这么做的话,递推起来又过于麻烦,可以突然想到只有1,0两种情况,一共的情况数是2^n,那么减掉0的情况不就是1的情况了吗!!!!被自己蠢哭了。。。

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <vector>#define MAX 2using namespace std;typedef long long LL;LL m,n,l,k;struct Matrix {    LL a[MAX][MAX];};void reset ( Matrix& m ){    memset ( m.a , 0 , sizeof ( m.a ) );}void set ( Matrix& m ){    memset ( m.a , 0 , sizeof ( m.a ) );    for ( int i = 0 ; i < 2 ; i++ )        m.a[i][i] = 1;}Matrix multi ( Matrix m1 , Matrix m2 ){    Matrix ret;    reset ( ret );    for ( int i = 0 ; i < 2 ; i++ )        for ( int j = 0 ; j < 2 ; j++ )            if ( m1.a[i][j] )                for ( int k = 0 ; k < 2 ; k++ )                    ret.a[i][k] = (ret.a[i][k] + m1.a[i][j] * m2.a[j][k]%m)%m;    return ret;}Matrix quickMulti ( Matrix m1 , LL n ){    Matrix ret;    set ( ret );    while ( n )     {        if ( n&1 ) ret = multi ( ret , m1 );        m1 = multi ( m1 , m1 );        n >>= 1;    }    return ret;}LL pow ( LL x , LL n ){    LL ret = 1;    while ( n )     {       if ( n&1 ) ret = ret*x%m;       x = x*x%m;       n >>= 1;     }    return ret;}Matrix a,b;LL ans;void init ( ){    reset ( b );    b.a[0][0] = b.a[0][1] = b.a[1][0] = 1;    ans = 1;}int main ( ){    while ( cin >> n >> k >> l >> m )     {        init();          b = quickMulti ( b , n+1 );        LL k1 = b.a[0][0];        LL k2 = ((pow (2,n)-k1)%m+m)%m;        int cnt = 0;        if ( m == 1 )        {            puts ("0");            continue;        }        if ( l < 63 && (1LL<<l) <= k )        {            puts ( "0" );            continue;        }        if ( l == 0 )        {            if ( k == 0 ) puts("1");            else puts("0");            continue;        }            while ( k )        {           if ( k&1 ) ans = ans*k2%m;           else ans = ans*k1%m;           k >>= 1;           cnt++;        }        while ( cnt++ < l )            ans = ans*k1%m;        ans = (ans%m+m)%m;        cout << ans << endl;    }}


0 0
原创粉丝点击