【ZOJ 3690】 Choosing number (矩阵快速幂)
There are n people standing in a row. And There are m numbers, 1.2...m. Every one should choose a number. But if two persons standing adjacent to each other choose the same number, the number shouldn't equal or less than k. Apart from this rule, there are no more limiting conditions.
And you need to calculate how many ways they can choose the numbers obeying the rule.
There are multiple test cases. Each case contain a line, containing three integer n (2 ≤ n ≤ 108), m (2 ≤ m ≤ 30000), k(0 ≤ k ≤ m).
One line for each case. The number of ways module 1000000007.
4 4 1
216
1 0 1
要注意k == m时m-k-1->0 k == 0时 k-1->0
然后用矩快就行了
代码如下:
#include <bits/stdc++.h> #define LL long long using namespace std; const int mod = 1e9+7; class Matrix { public: LL mt[3][3]; Matrix()//初始化空矩阵 { memset(mt,0,sizeof(mt)); } Matrix(int opt)//初始化单位矩阵 { memset(mt,0,sizeof(mt)); mt[0][0] = mt[1][1] = mt[2][2] = 1; } Matrix(int m,int k)//构造转移矩阵 { mt[0][0] = mt[0][2] = max(m-k-1,0); mt[0][1] = m-k; mt[1][0] = mt[1][2] = k; mt[1][1] = max(k-1,0); mt[2][0] = mt[2][2] = 1; mt[2][1] = 0; } Matrix operator *(const Matrix &x2)//矩阵乘法 { Matrix x; for(int i = 0; i < 3; ++i) for(int j = 0; j < 3; ++j) for(int k = 0; k < 3; ++k) x.mt[i][j] += (mt[i][k]*x2.mt[k][j])%mod; return x; } void output()//DeBug { for(int i = 0; i < 3; ++i) { for(int j = 0; j < 3; ++j) cout<<mt[i][j]<<' '; cout<<endl; } cout<<"--------------------"<<endl; } }; Matrix pow(Matrix x,int b)//矩阵乘法 { Matrix ans = Matrix(1); while(b) { if(b&1) ans = ans*x; b >>= 1; x = x*x; // ans.output(); } return ans; } int main() { int n,m,k; LL ans; while(~scanf("%d %d %d",&n,&m,&k)) { Matrix x = pow(Matrix(m,k),n-1); ans = 0; for(int i = 0; i < 3; ++i) { for(int j = 0; j < 2; ++j) { if(j == 0) ans = (ans+(m-k)*x.mt[i][j])%mod; else if(j == 1) ans = (ans+k*x.mt[i][j])%mod; } } printf("%lld\n",ans); } return 0; }
PS:发现递推式想麻烦了
直接dp[i][2]就够用
dp[i][0] 表示第i人选<=k的数的方案数
dp[i][1] 表示第i人选 >k 的数的方案数
dp[i][0] = dp[i-1][0]*(k-1)+dp[i-1][1]*k
dp[i][1] = (dp[i-1][0]+dp[i-1][1))*(m-k)
矩阵快速幂部分是大同小异的
代码如下:
#include <bits/stdc++.h> #define LL long long using namespace std; const int mod = 1e9+7; class Matrix { public: LL mt[2][2]; Matrix() { memset(mt,0,sizeof(mt)); } Matrix(int opt) { memset(mt,0,sizeof(mt)); mt[0][0] = mt[1][1] = 1; } Matrix(int m,int k) { mt[1][0] = mt[1][1] = m-k; mt[0][0] = max(k-1,0); mt[0][1] = k; } Matrix operator *(const Matrix &x2) { Matrix x; for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) for(int k = 0; k < 2; ++k) x.mt[i][j] += (mt[i][k]*x2.mt[k][j])%mod; return x; } void output() { for(int i = 0; i < 3; ++i) { for(int j = 0; j < 3; ++j) cout<<mt[i][j]<<' '; cout<<endl; } cout<<"--------------------"<<endl; } }; Matrix pow(Matrix x,int b) { Matrix ans = Matrix(1); while(b) { if(b&1) ans = ans*x; b >>= 1; x = x*x; // ans.output(); } return ans; } int main() { int n,m,k; LL ans; while(~scanf("%d %d %d",&n,&m,&k)) { Matrix x = pow(Matrix(m,k),n-1); ans = 0; for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) { if(j == 1) ans = (ans+(m-k)*x.mt[i][j])%mod; else if(j == 0) ans = (ans+k*x.mt[i][j])%mod; } } printf("%lld\n",ans); } return 0; }