矩阵快速幂 zoj-3690 Choosing number

 

题目链接:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4973

 

题目意思:

有n个人,有1——m个数,每个人可以选择1个数,要求相邻的两个人如果选的数相同则必须大于k,求选数的种数。

 

解题思路:

dp[n][1]表示第n个人选大于k的数的总的种数,dp[n][2]表示第n个人选<=k的数的总的种数。

则  dp[n][1]=(m-k)*dp[n-1][1]+(m-k)*dp[n-1][2]

      dp[n][2]=k*dp[n-1][1]+(k-1)*dp[n-1][2]

构造矩阵

m-k  m-k    dp[n-1][1]    dp[n][1]

 k      k-1      dp[n-1][2]       dp[n][2]

 

代码:

#include<iostream>

#include<cmath>

#include<cstdio>

#include<cstdlib>

#include<string>

#include<cstring>

#include<algorithm>

#include<vector>

#include<map>

#include<stack>

#include<list>

#include<queue>

#define eps 1e-6

#define INF (1<<30)

#define PI acos(-1.0)

using namespace std;



#define ll long long

#define mm  1000000007

/*

freopen("data.in","r",stdin);

freopen("data.out","w",stdout);

*/



//矩阵快速幂,快速幂



ll Mod(ll m,ll n)  //快速幂求m^n%mm

{

    ll res=1;



    while(n)

    {

        if(n&1)

            res=(res*m)%mm;

        m=(m*m)%mm;

        n=n>>1;

    }

    return res;

}





ll save[3][3];





int main()

{

    ll n,m,k;



    while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF)

    {

       if(k==0)

        {

            printf("%lld\n",Mod(m,n));

            continue;

        }

        if(n==1)

        {

            printf("%lld\n",m);

            continue;

        }



        save[1][1]=m-k,save[1][2]=m-k;

        save[2][1]=k,save[2][2]=k-1;



        ll ans1=m-k,ans2=k;

        n--;



        while(n)

        {

            if(n&1)

            {

               ll temp1=((save[1][1]*ans1)%mm+(save[1][2]*ans2)%mm)%mm;

               ll temp2=((save[2][1]*ans1)%mm+(save[2][2]*ans2)%mm)%mm;



               ans1=temp1;

               ans2=temp2;

            }

            n=n>>1;   //以后写矩阵相乘的话直接用三个循环来写,这样写的话容易出错

            ll a1=((save[1][1]*save[1][1])%mm+(save[1][2]*save[2][1])%mm)%mm;

            ll a2=((save[1][1]*save[1][2])%mm+(save[1][2]*save[2][2])%mm)%mm;

            ll b1=((save[2][1]*save[1][1])%mm+(save[2][2]*save[2][1])%mm)%mm;

            ll b2=((save[2][1]*save[1][2])%mm+(save[2][2]*save[2][2])%mm)%mm;



            save[1][1]=a1,save[1][2]=a2;

            save[2][1]=b1,save[2][2]=b2;



        }



        printf("%lld\n",(ans1+ans2)%mm);





    }

    return 0;

}














 

 

 

你可能感兴趣的:(number)