zoukankan      html  css  js  c++  java
  • Codeforces Round #307 (Div. 2) D. GukiZ and Binary Operations 矩阵快速幂优化dp

    D. GukiZ and Binary Operations
    time limit per test
    1 second
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    We all know that GukiZ often plays with arrays.

    Now he is thinking about this problem: how many arrays a, of length n, with non-negative elements strictly less then 2l meet the following condition: ? Here operation  means bitwise AND (in Pascalit is equivalent to and, in C/C++/Java/Python it is equivalent to &), operation  means bitwise OR (in Pascal it is equivalent to , in C/C++/Java/Python it is equivalent to |).

    Because the answer can be quite large, calculate it modulo m. This time GukiZ hasn't come up with solution, and needs you to help him!

    Input

    First and the only line of input contains four integers nklm (2 ≤ n ≤ 1018, 0 ≤ k ≤ 1018, 0 ≤ l ≤ 64, 1 ≤ m ≤ 109 + 7).

    Output

    In the single line print the number of arrays satisfying the condition above modulo m.

    Examples
    input
    2 1 2 10
    output
    3
    input
    2 1 1 3
    output
    1
    input
    3 3 2 10
    output
    9
    Note

    In the first sample, satisfying arrays are {1, 1}, {3, 1}, {1, 3}.

    In the second sample, only satisfying array is {1, 1}.

    In the third sample, satisfying arrays are {0, 3, 3}, {1, 3, 2}, {1, 3, 3}, {2, 3, 1}, {2, 3, 3}, {3, 3, 0}, {3, 3, 1}, {3, 3, 2}, {3, 3, 3}.

    思路:首先看到或,并就想将这个数拆开为二进制的01串,分别考虑每一位的0,1;

       当前k的那个位置为0时,表示a1-an中没有两个相邻的1;

       同理,当前k为为1时,表示a1-an中有两个相邻的1;2^n,减去0的方案即是;

       刚刚开始一直在想组合数学的求法,发现不好写(。。。我也不会)

       后来发现dp可以做,但是n很大;

       dp方程:dp[i][0]=dp[i-1][1]+dp[i-1][0];

           dp[i][1]=dp[i-1][0];

       dp[i][j]表示第i位为j的无相邻1的方案数;

       乍一看很像斐波那契,构造矩阵;

                     [  1  ,   1   ]

       [ dp[i-1][0] , dp[i-1][1] ]  *[  1  ,   0   ]     =[   dp[i][0]   ,   dp[i][1]   ];

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define pi (4*atan(1.0))
    #define eps 1e-14
    #define bug(x,y) cout<<"bug"<<x<<" "<<y<<endl;
    #define bug(x) cout<<"xxx "<<x<<endl;
    const int N=1e5+10,M=1e6+10,inf=2e9+10,mod=1e9+7;
    const ll INF=1e18+10;
    ll MOD;
    struct Matrix
    {
        ll a[2][2];
        Matrix()
        {
            memset(a,0,sizeof(a));
        }
        void init()
        {
            for(int i=0;i<2;i++)
                for(int j=0;j<2;j++)
                    a[i][j]=(i==j);
        }
        Matrix operator + (const Matrix &B)const
        {
            Matrix C;
            for(int i=0;i<2;i++)
                for(int j=0;j<2;j++)
                    C.a[i][j]=(a[i][j]+B.a[i][j])%MOD;
            return C;
        }
        Matrix operator * (const Matrix &B)const
        {
            Matrix C;
            for(int i=0;i<2;i++)
                for(int k=0;k<2;k++)
                    for(int j=0;j<2;j++)
                        C.a[i][j]=(C.a[i][j]+1LL*a[i][k]*B.a[k][j])%MOD;
            return C;
        }
        Matrix operator ^ (const ll &t)const
        {
            Matrix A=(*this),res;
            res.init();
            ll p=t;
            while(p)
            {
                if(p&1)res=res*A;
                A=A*A;
                p>>=1;
            }
            return res;
        }
    };
    ll quickmod(ll a,ll b,ll c)
    {
        ll ans=1;
        while(b)
        {
            if(b&1)ans=(ans*a)%c;
            b>>=1;
            a=(a*a)%c;
        }
        return ans;
    }
    int main()
    {
        ll n,k,m,l;
        cin>>n>>k>>l>>m;
        MOD=m;
        Matrix base,ans;
        base.a[0][0]=base.a[0][1]=base.a[1][0]=1;
        base.a[1][1]=0;
        ans.a[0][0]=ans.a[0][1]=1;
        ans.a[1][0]=ans.a[1][1]=0;
        ans=ans*(base^(n-1));
        ll zero=(ans.a[0][0]+ans.a[0][1])%m;
        ll one=((quickmod(2LL,n,m)-zero)%m+m)%m;
        //cout<<zero<<" "<<one<<endl;
        ll out=1;
        if((l<=62&&k>=(1LL<<l)))return puts("0");
        for(ll i=l-1;i>=0;i--)
        {
            if(i>60)
                out*=zero;
            else
            {
                ll x=(1LL<<i)&k;
                if(x)
                    out*=one;
                else
                    out*=zero;
            }
            out%=m;
        }
        printf("%lld
    ",out%m);
        return 0;
    }
  • 相关阅读:
    【华为云技术分享】浅谈服务化和微服务化(上)
    STM32 GPIO的原理、特性、选型和配置
    【华为云技术分享】如何设计高质量软件-领域驱动设计DDD(Domain-Driven Design)学习心得
    【华为云技术分享】如何做一个优秀软件-可扩展的架构,良好的编码,可信的过程
    【华为云技术分享】华为云MySQL新增MDL锁视图特性,快速定位元数据锁问题
    如何使网站支持https
    如何说孩子才会听,怎么听孩子才肯说
    box-sizing布局学习笔记
    vertical-align属性笔记
    Github上整理的日常发现的好资源【转】
  • 原文地址:https://www.cnblogs.com/jhz033/p/6417099.html
Copyright © 2011-2022 走看看