Queues and Priority Queues are data structures which are known to most computer scientists. The Queue occurs often in our daily life. There are many people lined up at the lunch time.
Now we define that ‘f’ is short for female and ‘m’ is short for male. If the queue’s length is L, then there are 2 L numbers of queues. For example, if L = 2, then they are ff, mm, fm, mf . If there exists a subqueue as fmf or fff, we call it O-queue else it is a E-queue.
Your task is to calculate the number of E-queues mod M with length L by writing a program.
Input
Input a length L (0 <= L <= 10 6) and M.
Output
Output K mod M(1 <= M <= 30) where K is the number of E-queues with length L.
Sample Input
3 8
4 7
4 8
Sample Output
6
2
1
题意: 给你一个数L代表一个队的长度,男女不限,随便排,f代表女生,m代表男生,但是其中不能出现 fmf 、fff 这种子序列,问一共有多少种排的方法,结果需要mod m.
题解: 任意L ,因为不存在fmf,fff所以可以这样想:
1. 最后一个为m 那么有 f(L-1) 个这种情况的。
2.最后为mmf 那么有 f(L-3) 个这种情况的。
3.最后为mmff 那么有 f(L-4) 个这种情况的。
只有满足上面三种情况,才符合题意。 所以我们可以得出递推关系,f(L) = f(L-1) + f(L-3) + f(L-4). 但是我们需要找出前四个的种类数,也是比较好找了,他们是2,4,6,9 , L为4可能比较难找,但是通过给的样例可以发现,设L为4的时候有x种,那么根据样例可以得出x%7=2,x%8=1 所以 x=9。这样我们可以根据递推式写一种带有技巧的代码:
#include <iostream>
using namespace std;
int f[1000005];
int main(){
f[1]=2;//前四个需要单独算出来
f[2]=4;
f[3]=6;
f[4]=9;
int l,m;
while(cin >> l >> m){
for (int i = 5; i <= l;i++){
f[i]=f[i-1]+f[i-3]+f[i-4];//递推式
if(f[i] > 10000){//这里控制,取模运算次数,也控制f[i]的大小,如果f[i]大于m就取模会超时,这也算是小技巧了
f[i]%=m;
}
}
cout << f[l]%m << endl;
}
return 0;
}
下面看一下正规做法,用到了矩阵快速幂。
矩阵快速幂关键是构造矩阵,怎么构造呢? 通过递推式构造,应该有递推式的题都应该想到矩阵快速幂(个人见解)。够造的时候需要连续(个人见解)就是说 f(L) = f(L-1) + f(L-3) + f(L-4).需要写成f(L) = f(L-1) + 0* f(L-2) + f(L-3) + f(L-4).然后开始构造。。
f(L-1) 1 0 1 1 f(L)
f(L-2) 1 0 0 0 f(L-1)
f(L-3) 0 1 0 0 f(L-2)
f(L-4) 0 0 1 0 f(L-3)
红色部分就是我们要的矩阵,剩下来的就好做了,需要的是“构造矩阵”的L-5+1次方的第一行乘以9,6,4,2然后相加就可以了,注意小与5需要单独考虑。上代码。
#include <iostream>
#include <cstring>
using namespace std;
struct hh{
int a[20][20];
}x;
int p[5]={0,2,4,6,9};//用于单独考虑输出
int r[5]={9,6,4,2};//储存前四项后面有用
hh mul(hh x,hh y,int c){//矩阵快速幂
hh w;
memset(w.a,0,sizeof(w.a));//初始化别忘记
for (int i = 0; i < 4;i++){
for (int j= 0; j < 4;j++){
for (int k = 0; k < 4; k++){
w.a[i][j]=(w.a[i][j]%c+(x.a[i][k]%c*y.a[k][j]%c)%c)%c;
}
}
}
return w;
}
hh j_quick(hh a, int b,int c){//矩阵快速幂
hh ans;
memset(ans.a,0,sizeof(ans.a));//初始化别忘记
for (int i = 0; i < 4;i++){
ans.a[i][i]=1;
}
while(b!=0){
if(b&1) ans=mul(ans,a,c);
b>>=1;
a=mul(a,a,c);
}
return ans;
}
int main(){
int l,m;
while(cin >> l >> m){
if(l<5){//单独考虑输出部分
cout << p[l]%m << endl;
continue;
}
memset(x.a,0,sizeof(x.a));
for (int i = 0; i < 4;i++){//构造矩阵
if(i!=1) x.a[0][i]=1;
if(i<3) x.a[i+1][i]=1;
}
hh z=j_quick(x,l-5+1,m);//计算“构造矩阵”的l-5+1次方
int sum=0;
for (int i = 0; i < 4;i++){//第一行乘以9,6,4,2,然后加和, 用到前面的r[5]
sum=(sum%m+(r[i]%m*z.a[0][i]%m)%m)%m;
}
cout << sum << endl;
}
return 0;
}