HDU——2604 Queuing(矩阵快速幂或者技巧题)

     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 , L4可能比较难找,但是通过给的样例可以发现,设L4的时候有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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心脏dance

如果解决了您的疑惑,谢谢打赏呦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值