• 矩阵快速幂 zoj3690 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;
    }
    
    
    
    
    
    
    


     

  • 相关阅读:
    纯awk传参和awk脚本传参
    【转】MySQL 备份和恢复(MyISAM 和 Innodb)
    【z】多线程Java Socket编程示例
    Java,Tomcat,Mysql乱码总结
    mysql备份与同步shell脚本
    【转】Velocity用户手册中文版(学习修改版)
    wml新学的标签
    【原】小心log4j的多进程写入
    【z】Webservice 的设计和模式
    【z】linux面试题参考答案
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/2999194.html
Copyright © 2020-2023  润新知