View on GitHub

Wenchong Huang

旧博客,文章搬迁完后删除

返回首页 返回专题

【LuoguP1707】刷题比赛 题解

这道题真的是非常非常非常地令人痛苦!

手写了一个11*11的递推矩阵,仿佛身体被掏空……

首先看到这个数据范围,就知道这题应该要写一个复杂度大概O(log N)的算法才能A

看到这种递推数列,而且时间复杂度要求那么苛刻的,肯定就是要用矩阵加速

那么我们来思考怎么构造矩阵

下面这个是我构造的初始状态矩阵(当然肯定有更加优雅的构造方法,毕竟我太菜了)

接下来就是构造递推矩阵

这题的恶心之处就在于后面那一大堆次方数的处理

可以说这样的递推数列真是丑陋不堪

直接上我构造的递推矩阵吧,可以自己手算矩阵乘法验证一下我的递推矩阵

思路当然是将上面的初始状态矩阵里面的数据看做已知量,通过这些已知量推出未知量

为了防止出现负数,构造完这个递推矩阵后要 (每个数%Mod+Mod)%Mod

由于模数太大了,边乘边模会爆掉,所以还要写一个快速乘,把乘法转换成加法……

所以最终代码的时间复杂度为O(dlog Nlog Mod)

其中d是常数,由于递推矩阵过于庞大,算法的常数高达1331(就是11的3次方),因此不能忽略这个常数

然而如此糟糕的时间复杂度还是在100ms内轻松A掉了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

typedef long long LL;
LL Mod;

struct Matrix
{
	int m,n;
	LL a[20][20];
	Matrix(int _m=0,int _n=0):m(_m),n(_n){}
};

LL QuickMul(LL a,LL b)
{
	LL ans=0;
	while(b)
	{
		if(b&1) ans=(ans+a)%Mod;
		a=(a+a)%Mod;
		b>>=1;
	}
	return ans;
}

Matrix operator * (Matrix a,Matrix b)
{
	if(a.n!=b.m) return Matrix(0,0);
	Matrix ans;
	ans.m=a.m;
	ans.n=b.n;
	for(int i=1;i<=a.m;i++)
		for(int j=1;j<=b.n;j++)
		{
			ans.a[i][j]=0;
			for(int k=1;k<=a.n;k++) ans.a[i][j]=(ans.a[i][j]+QuickMul(a.a[i][k],b.a[k][j]))%Mod;
		}
	return ans;
}

Matrix QuickPow(Matrix a,LL b)
{
	if(b==0) return Matrix(0,0);
	Matrix ans=a;
	b--;
	while(b)
	{
		if(b&1) ans=ans*a;
		a=a*a;
		b>>=1;
	}
	return ans;
}

int main()
{
	LL n;
	LL p,q,r,t,u,v,w,x,y,z;
	cin>>n>>Mod>>p>>q>>r>>t>>u>>v>>w>>x>>y>>z;
	Matrix A;
	A.m=A.n=11;
	memset(A.a,0,sizeof(A.a));
	A.a[1][1]=p;A.a[1][2]=1;A.a[1][3]=1;A.a[1][4]=q;A.a[1][7]=r;A.a[1][8]=t-2*r;A.a[1][11]=r-t+1;
	A.a[2][1]=1;A.a[2][2]=u;A.a[2][3]=1;A.a[2][5]=v;A.a[2][9]=1;
	A.a[3][1]=1;A.a[3][2]=1;A.a[3][3]=x;A.a[3][6]=y;A.a[3][8]=1;A.a[3][10]=1;A.a[3][11]=1;
	A.a[4][1]=1;A.a[5][2]=1;A.a[6][3]=1;
	A.a[7][7]=1;A.a[7][8]=2;A.a[7][11]=1;
	A.a[8][8]=1;A.a[8][11]=1;
	A.a[9][9]=w;A.a[10][10]=z;A.a[11][11]=1;
	for(int i=1;i<=11;i++)
		for(int j=1;j<=11;j++) A.a[i][j]=(A.a[i][j]%Mod+Mod)%Mod;
	A=QuickPow(A,n-2);
	Matrix ans;
	ans.m=11;
	ans.n=1;
	ans.a[1][1]=3;ans.a[2][1]=3;ans.a[3][1]=3;
	ans.a[4][1]=1;ans.a[5][1]=1;ans.a[6][1]=1;
	ans.a[7][1]=4;
	ans.a[8][1]=2;
	ans.a[9][1]=w%Mod;
	ans.a[10][1]=z%Mod;
	ans.a[11][1]=1;
	ans=A*ans;
	cout<<"nodgd "<<ans.a[1][1]<<endl;
	cout<<"Ciocio "<<ans.a[2][1]<<endl;
	cout<<"Nicole "<<ans.a[3][1]<<endl;
	return 0;
}