ZOJ 2573 DNA Problem(矩阵快速幂)

题意:

基因题意:
N个基因 经过M次突变 A代表S1,B代表S2,
比如第一组数据,它的突变顺序就是S1,S2,S2,S1,S2,S2....我们要输出经过M次变异后的基因
接下来不是有两个N*N的东西吗,第一个就是代表S1,第二个代表S2,举个例子
0 1 0
0 1 1
0 1 0

(横着是i,竖着是j)

当i=0时,如何判断第i个基因是alive还是dead,就看相应的j了。j从0~n-1,位置(i,j)对应的值是1,且j位置对应的基因是alive的那么就s++,最终的s是奇数,i基因就是alive,否则就是dead,
以上就是一次变异
(特别绕,有点晕)
 
解题思路:
输入原始基因,将它转化为数组pi[ ],alive为1,,dead为0
要求的表达式是   pi*s1...*s2*s1*...*s2*...(M个s1,s2)    ===>有奇偶,对2取余
针对这个式子,我们可以先算出A个s1相乘,记为q1,再算出B个s2相乘,记为q2,
q3是q1*q2
求出M/(A+B)个q3的乘积
再将零碎的s1,s2乘起来,与pi相乘
最终的结果就是1代表alive,0代表dead

还有一点要注意的是s1,s2,横的变为竖的,看代码上的标记

 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
int n;
struct mat
{
	int e[55][55];
};
mat mul(mat a, mat b)
{
	mat ret;
	memset(ret.e,0,sizeof(ret.e));
	for(int i=0;i<n;i++)
		for(int k=0;k<n;k++)
		if(a.e[i][k])
			for(int j=0;j<n;j++)
			if(b.e[k][j])
			ret.e[i][j] = (ret.e[i][j]+a.e[i][k]*b.e[k][j])%2;
	return ret;
}
mat mpower(mat C,int m)
{
	mat I;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			I.e[i][j] = (i==j);
	while(m)
	{
		if(m&1) I = mul(I,C);
		m>>=1;
		C = mul(C,C);
	}
	return I;
}
int main()
{
	int m,A,B;
	while(cin>>n>>m>>A>>B)
	{
		mat a,b;
		mat pi;
		char s[10];
		int t[5][55];
		memset(t,0,sizeof(t));
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				cin>>a.e[j][i];//把相应的位置变为一列一列的,否则会错 ,下面一样 
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				cin>>b.e[j][i];
		for(int i=0;i<n;i++)
		{
			scanf("%s",s);
			if(s[0]=='a') pi.e[0][i]=1;
			else pi.e[0][i]=0;
		}
		int tem = m/(A+B);
		mat q1 = mpower(a,A);
		mat q2 = mpower(b,B);
		mat q3 = mul(q1,q2);
		mat q4 = mpower(q3,tem);
		mat q5 = mpower(a,min(m-tem*(A+B),A));
		mat q6 = mpower(b,max(m-tem*(A+B)-A,0));
		mat q7 = mul(q4,q5);
		mat q8 = mul(q7,q6);
		for(int i=0;i<1;i++)
			for(int k=0;k<n;k++)
			if(pi.e[i][k])
				for(int j=0;j<n;j++)
				if(q8.e[k][j])
				t[i][j] = (t[i][j]+pi.e[i][k]*q8.e[k][j])%2;
		for(int i=0;i<n-1;i++)
		{
			if(t[0][i]==1) cout<<"alive"<<" ";
			else cout<<"dead"<<" ";
		}
		if(t[0][n-1]==1) cout<<"alive"<<endl;
		else cout<<"dead"<<endl;
	}
	return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值