[计蒜客]2019 ICPC 南昌网络赛 H(矩阵快速幂)

传送门:https://nanti.jisuanke.com/t/41355

题意:

给定q,N1,求F[N1] xor F[N2] xor ··· xor F[Nq]。其中,Ni=N(i-1) xor (F[N(i-1)]*F[N(i-1)])。

分析:

显然,要用到矩阵快速幂来计算F[n],可推得\left[\begin{matrix}F[n] \\F[n-1]\end{matrix}\right]\tag{3}= \left[\begin{matrix}3\2\\1\0\end{matrix}\right]\tag{3}^{n-1} \left[\begin{matrix}F[1] \\F[0]\end{matrix}\right]\tag{3}

但是写完发现如果q>10^{5}会超时。想了一下午如何加速,最后发现始终突破不了10^{5}。最终尝试用10进制的矩阵快速幂,但还是不行。比赛结束后在某个群里看到有人说这题加个if(q>100000) q=100000就行了。因为异或下去某个Ni=0时后面的结果保持不变。(很难受~~)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=2;
struct mat{
	ll m[maxn][maxn];
}unit;
mat operator *(mat a,mat b){
	mat res;
	memset(res.m,0,sizeof(res.m));
	for(int i=0;i<maxn;i++){
		for(int j=0;j<maxn;j++){
			for(int k=0;k<maxn;k++){
				res.m[i][j]=(res.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
			}
		}
	}
	return res;
}
void init(){
	for(int i=0;i<maxn;i++)
		unit.m[i][i]=1;
}
mat pow_mat(mat x,ll n){
	if(n>499122176)
		n%=499122176;
	int v[20],j=0;
	ll h=n;
	while(h){
		v[++j]=h%10;
		h/=10;
	}
	mat res=unit;
	for(int k=1;k<=j;k++){
		for(int i=1;i<=v[k];i++){
			res=res*x;
		}
		mat c[2];
		x=x*x;
		c[0]=x*x;
		c[1]=c[0]*c[0];
		x=x*c[1];
	}
	return res;
}
int main(){
	ll q,n;
	init();
	scanf("%lld %lld",&q,&n);
	if(q>100000)
		q=100000;
	mat a;	
	a.m[0][0]=3;	
	a.m[0][1]=2;
	a.m[1][0]=1;
	a.m[1][1]=0;
	ll t,ans=0,k;
	mat res;
	for(int i=1;i<=q;i++){
		res=pow_mat(a,n-1);
		t=res.m[0][0];
		if(t!=0){
			ans=ans xor t;
			n=((t*t)) xor n;
		}
	}
	printf("%lld\n",ans);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值