(Small)S[ i ] 前i个数字排列的方案数 (最后一位小于等于K)
(Big) B[ i ] 前i个数字排列的方案数 (最后一个数字大于K)
递推公式 :
S[ i ] = S[ i-1 ]*(K-1) + B[ i-1 ]*K
B[ i ] = S[ i-1 ]*(M-K) + B[ i-1 ]*(M-K)
最终总方案数为S[N]+B[N]
可惜由于N的范围太广 ,直接滚动求解超时
注意下面的乘法
K-1 K S[i-1] S[i]
x =
M-K M-K B[i-1] B[i]
N次这样的矩阵相乘可以用快速幂来实现,log2(n)。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MOD 1000000007
int N,M,K;
struct Mat{
unsigned long long m11,m12,m21,m22;
};
Mat Mul(Mat a,Mat b){ //2x2矩阵乘法
Mat ret={
(a.m11*b.m11%MOD+a.m12*b.m21%MOD)%MOD, (a.m11*b.m12%MOD+a.m12*b.m22%MOD)%MOD,
(a.m21*b.m11%MOD+a.m22*b.m21%MOD)%MOD, (a.m21*b.m12%MOD+a.m22*b.m22%MOD)%MOD
};
return ret;
}
int main()
{
int i,j,k;
while(scanf("%d%d%d",&N,&M,&K)!=EOF)
{
Mat o={1,0,0,1}; //单位矩阵
Mat t={ //矩阵基本单元
K-1, K,
M-K, M-K
};
N--;
while(N>0)
{
if(N&1)
o=Mul(o,t);
N>>=1;
t=Mul(t,t);
}
printf("%llu\n",(o.m11*K%MOD+o.m12*(M-K)%MOD+o.m21*K%MOD+o.m22*(M-K)%MOD)%MOD);
}
return 0;
}
ZOJ好像用不了 __int64