BZOJ:3231: [Sdoi2008]递归数列

题解:

矩阵乘法,在矩阵中构造当前前缀和;

注意:for(int/long long ;;);

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long Lint;

Lint n,m;
int k,p;
int b[200];
int c[200];
Lint tmp1,tmp2;
Lint sum;
int minit(){
	tmp1=tmp2=sum=0;
}

struct Matrix{
	Lint e[200][200];
	Matrix(){
		memset(e,0,sizeof(e));
	}
	int clear(){
		memset(e,0,sizeof(e));
	}
}t,x,y,z,ret;

int Mul(){
	z.clear();
	for(int i=0;i<=k;++i){
		for(int j=0;j<=k;++j){
			for(int r=0;r<=k;++r){
				z.e[i][j]=(z.e[i][j]+x.e[i][r]*y.e[r][j])%p;
			}
		}
	}
}

int Ksm(Lint p){
	ret.clear();
	for(int i=0;i<=k;++i)ret.e[i][i]=1;
	while(p){
		if(p<0)return 0;
		if(p&1){
			x=ret;y=t;Mul();
			ret=z;
		}
		p>>=1;
		x=t;y=t;Mul();
		t=z;
	}
}

int main(){
	minit();
	
	scanf("%d",&k);
	for(int i=1;i<=k;++i)scanf("%d",&b[i]);
	for(int i=1;i<=k;++i)scanf("%d",&c[i]);
	scanf("%lld%lld%d",&n,&m,&p);
	for(int i=1;i<=k;++i)sum=(sum+b[i])%p;
	
	if(m<=k){
		for(int i=n;i<=m;++i)tmp1=(tmp1+b[i])%p;
		printf("%lld\n",tmp1);
		return 0;
	}else{
		
		for(Lint i=n;i<=k;++i)tmp2=(tmp2+b[i])%p;
		n=max(n,k+1LL);
		
		for(int i=1;i<=k;++i)t.e[1][i]=t.e[0][i]=c[i];
		for(int i=2;i<=k;++i)t.e[i][i-1]=1;
		t.e[0][0]=1;
		Ksm(n-k-1);
		
		for(int i=1;i<=k;++i){
			tmp1=(tmp1+ret.e[0][i]*b[k-i+1])%p;
		}
		tmp1=(tmp1+sum*ret.e[0][0])%p;
		
		t.clear();
		for(int i=1;i<=k;++i)t.e[1][i]=t.e[0][i]=c[i];
		for(int i=2;i<=k;++i)t.e[i][i-1]=1;
		t.e[0][0]=1;
		Ksm(m-k);
		
		for(int i=1;i<=k;++i)tmp2=(tmp2+ret.e[0][i]*b[k-i+1]%p)%p;
		tmp2=(tmp2+sum*ret.e[0][0])%p;
		
		printf("%lld\n",(tmp2-tmp1+p)%p);
		return 0;
	}
}

  

posted @ 2018-01-02 21:48  ws_zzy  阅读(170)  评论(0编辑  收藏  举报