Number of Battlefields UVA - 11885 矩阵快速幂(高斯消元解线性递推)

本文探讨了一道关于寻找周长特定的非矩形图形数量的问题,通过排除矩形并利用Berlekamp-Massey算法推导非线性递推公式,揭示了答案与斐波那契数列偶数项的关系。暴力打表和高斯消元方法展示了求解过程,适用于递推序列的线性化求解。
摘要由CSDN通过智能技术生成

Number of Battlefields UVA - 11885

题目大意:给出周长p,问多少种形状的周长为p的,并且该图形的最小包围矩阵的周长也是p,不包括矩形。

假题解:如果包含矩形的话,对应的则是斐波那契数列的偶数项,所以对应减去矩形的个数即可。
讲道理,搜了很多很多博客,都没有讲斐波那契是怎么推的。
可能有人就是想到加上那个包括矩形的数量打个表看看,然后发现了这是斐波那契数列的偶数项。 (我觉得这个可能性大点)

也可能是根据题目给的性质推的。
首先显然奇数项都是0,这里只讨论偶数项。
这里给出一个不是斐波那契的递推,
前面四项:
2 9 29 83
f n = 5 f n − 1 − 8 f n − 2 + 5 f n − 3 − f n − 4 f_{n}=5f_{n-1}-8f_{n-2}+5f_{n-3}-f_{n-4} fn=5fn18fn2+5fn3fn4

它怎么来的呢?
已知前k项求最短递推式可以用Berlekamp-Massey算法
洛谷模板题
模板(看5.3)
所以本题解完结。
.

.

.
但是BM算法好像太难了。
我们通过暴力打表得到了前k项的值 f k f_k fk。如果我们认为它是线性递推,
我们可以设
f n = x 1 ∗ f n − 1 + x 2 ∗ f n − 2 + x 3 ∗ f n − 3 + x 4 ∗ f n − 4 . . . f_{n}=x_1*f_{n-1}+x_2*f_{n-2}+x_3*f_{n-3}+x_4*f_{n-4}... fn=x1fn1+x2fn2+x3fn3+x4fn4...
即有
( f 1 f 2 f 3 . . . f t f 2 f 3 f 4 . . . f t + 1 f 3 f 4 f 5 . . . f t + 2 . . . f t f t + 1 f t + 2 . . . f t + t ) ( x 1 x 2 x 3 . . . x t ) = ( f t + 1 f t + 2 f t + 3 . . . f t + t + 1 ) \begin{pmatrix} f_1 & f_2 & f_3 & ...& f_t\\ f_2 & f_3 & f_4 & ...& f_{t+1}\\ f_3 & f_4 & f_5 & ...& f_{t+2}\\ ...\\ f_t &f_{t+1} &f_{t+2} &... &f_{t+t} \end{pmatrix} \begin{pmatrix} x_1 \\ x_2\\x_3\\... \\ x_t\end{pmatrix} = \begin{pmatrix} f_{t+1} \\ f_{t+2}\\f_{t+3}\\...\\f_{t+t+1} \end{pmatrix} f1f2f3...ftf2f3f4ft+1f3f4f5ft+2............ftft+1ft+2ft+tx1x2x3...xt=ft+1ft+2ft+3...ft+t+1
所以用高斯消元解如上方程组即可得到 x 1 , x 2 , x 3 , . . . x_1,x_2,x_3,... x1,x2,x3,...的系数,从而求出递推式。
那我们不知道递推式有多少项怎么办。只要我们给出的项足够多。那么上面那个递推方程就会有自由未知元,我们可以令自由未知元为0从而构造出递推方程。
或者直接在高斯消元的过程中,只要找到全0行,那也说明递推式的值已经可以全部确定。(不会证明)
例如,斐波那契递推解的过程:
斐波那契数列递推的求解
上图红框处是解的结果。

BM算法求解的时间复杂度是 O ( k 2 ) O(k^2) O(k2),高斯消元显然是 O ( k 3 ) O(k^3) O(k3), k k k是递推式的“长度”。已知递推式求第n项就可以有各种方法啦。

一下是vjudge上ac的代码。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define rep(i,a,b) for(int i=a;i<b;i++)
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
#include<queue>
using namespace std;
ll mod=1e9+7;
typedef vector<ll> vec;
typedef vector<vec> mat;
ll n,k;
ll qpow(ll x,ll n){//快速幂
	ll c=1;
	for(x%=mod;n;n/=2,x=x*x%mod) if(n&1) c=c*x%mod;
	return c;
}
int N;
void mul(mat&a,mat&b){//矩阵乘法
	mat c(N,vec(N));
	rep(i,0,N) rep(j,0,N) rep(k,0,N)
		(c[i][j]+=a[i][k]*b[k][j])%=mod;
	a=c;
}
void qpow(mat&a,ll n){//矩阵快速幂
	mat gg(N,vec(N));rep(i,0,N) gg[i][i]=1;
	for(;n;n/=2,mul(a,a)) if(n&1) mul(gg,a);
	a=gg;
}
//高斯消元求解线性递推方程
vec gauss(vec xn){//传入的是前多项的系数
	N=xn.size()/2;
	mat dt(N,vec(N));
	rep(i,0,N) rep(j,0,N) dt[i][j]=xn[i+j];//构造矩阵
	int r=0,p=r;
	for(;r<N;r++){
		for(p=r;p<N;p++) if(dt[p][r]) break;//找到该列非0的行
		if(p==N) break;
		swap(dt[p],dt[r]);
		ll ap=qpow(dt[r][r],mod-2);
		rep(j,r,N) dt[r][j]=dt[r][j]*ap%mod;
		rep(i,0,N) if(i!=r){
			ap=dt[i][r];
			rep(j,r,N) dt[i][j]=((dt[i][j]-dt[r][j]*ap)%mod+mod)%mod;
		}
	}
	vec res;
	rep(i,0,r) res.push_back(dt[r-1-i][r]);//把第r列的解拿出来
	return res;
}
//以下是暴力打表求解
int jjj(deque<int> v){
	while(v.size()>1&&v.front()<=v[1]) v.pop_front();//左递增
	while(v.size()>1&&v.back()<=v[v.size()-2]) v.pop_back();//右递减
	return v.size()==1;//单峰
}
ll count_(int x){
	x/=2;
	ll ret=0;
	for(int col=2;col<x-1;col++){//枚举列
		int lin=x-col;
		ll pa=qpow(lin,col);
		for(int i=0;i<pa-1;i++){
			deque<int> d;
			int t=i;
			do d.push_back(t%lin),t/=lin;while(t);
			if(*max_element(d.begin(),d.end())!=lin-1) continue;
			ret+=jjj(d);
		}
	}
	return ret;
}
//以上是暴力打表求解
int main(){//ve是暴力打表结果
	vec ve{2,9,29,83,226,602,1588,4171,10935,28645,75012};
	// for(int i=8;i<30;i+=2) printf("%lld %d\n",count_(i),i),ve.push_back(count_(i));
	vec res=gauss(ve);//求解递推式
	N=res.size();//递推式的长度
	mat init(N,vec(N));//构造递推矩阵
	rep(i,0,N) init[0][i]=res[i]>987654321?(987654321-(mod-res[i])):res[i];
	rep(i,1,N) init[i][i-1]=1;
	mod=987654321;
	ll n;
	while(scanf("%lld",&n),n){
		if(n&1||n<8) {puts("0");continue;}
		n=n/2-3;
		if(n<N) printf("%lld\n",ve[n-1]);
		else {
			mat t=init;
			qpow(t,n-N);
			ll sum=0;
			for(int i=0;i<N;i++) sum=(sum+t[0][i]*ve[N-1-i])%987654321;
			printf("%lld\n",sum);
		}
	}
}

目前这个板子并没有做太多的测试,不能保证正确性。
大概就是懂其原理即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值