zoj 3690 Choosing number

题意    就是说给你 N 个人站成一排,现在每个人都可以选择 1~M 中间的任意一个数字,相邻的两个人数字相同,则他必须是是 >  K 的  问方案总数;

方法    先求出递推式,然后用矩阵快速 mo mi  构造矩阵 时候很简单  递推方程式为   f(n) = f(n-1)*M - f( n-1 ) + f( n-2 )*( m - k ) 就是当前这个人必定是从前面那个人的所有组合数中满足条件的数量  × M 得到当前这个人的所有状态 但还需要减去 前面那个人有多少个是 以 <=K  结尾 的总数; 方法是 前面那个状态记录了所有满足的状态,前面 ( n - 2 )×( m - k ) 记录了上一个状态有多少是大于 K 结尾的  总数 减去  <= k  的便是小于的;

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define mod 1000000007
using namespace std;

struct date {
    long long X[3][3];
}tab;
long long lt,rt,up,dn,N,M,K;
date mix( date a,date b )
{
     date c;
     for( int i = dn; i <= up; i++ ) // 纵坐标 从上到下
     for( int j = lt; j <= rt; j++ ) // 横坐标 从左到右
     {
         c.X[i][j] = 0;
         for( int k = lt; k <= rt; k++ )
         c.X[i][j] =  (c.X[i][j] + (a.X[i][k]*b.X[k][j])%mod)%mod;
     }
     return c;
}
date work( int N )
{
     if( N == 1 )return tab;
       date a = work( N/2 );
     a = mix( a,a );
     if( N%2 ) a = mix( tab,a );
     return a;
}
int main( )
{
    while( scanf("%lld%lld%lld",&N,&M,&K) != EOF )
    {
        tab.X[0][0] = 0; tab.X[0][1] = M-K;
        tab.X[1][0] = 1; tab.X[1][1] = M-1;
        lt = 0; rt = 1; dn = 0; up = 1;
        date a = work( N-1 );
        //cout<<a.X[0][0]<<" "<<a.X[0][1]<<" "<<a.X[1][0]<<" "<<a.X[1][1]<<endl;
        date b; b.X[0][0] = M; b.X[0][1] = M*M - K;
                b.X[1][0] = 0; b.X[1][1] = 0;
        date c = mix( b,a  );
        printf("%lld\n",c.X[0][0]);
    }
    return 0;
}

 


 

posted on 2013-08-24 20:30  浪舟  阅读(228)  评论(0编辑  收藏  举报

导航