您的位置:首页 > 运维架构

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

2015-06-21 13:48 417 查看
题目链接:

罪恶的链接

题目大意:

有一个数组,(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 2

using 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;
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: