『STA - R3』高维立方体 题解

这题的部分分比较好拿,就不细讲了。

Subtask 3 经过简单的推导可以发现这个式子的值一定是偶数,直接输出 \(0\) 即可。

Subtask 4 求出这个式子的循环节。

Subtask 5 可以用一个大矩阵快速幂做,比较麻烦。

先考虑怎么求 \(\sum_{i=1}^{n}\operatorname{fib}^2(i)\)。如图,我们可以用若干个正方形的面积和来表示:

可以发现这个长方形的长是 \(\operatorname{fib}(n+1)\),宽是 \(\operatorname{fib}(n)\),得到:

\[\sum_{i=1}^{n}\operatorname{fib}^2(i)=\operatorname{fib}(n)\operatorname{fib}(n+1) \]

看到三个数的乘积我们可以想到立方体,上图(可能画得比较丑):

如果最大的立方体边长是 \(\operatorname{fib}(n)\),那么红色部份的体积就是 \(\operatorname{fib}(n)\operatorname{fib}(n-1)\operatorname{fib}(n-2)\),于是:

\[\begin{aligned} \sum_{i=1}^n\operatorname{fib}(i)\cdot(f(i-2)+\operatorname{fib}^2(i)+\operatorname{fib}(i))&= \left(\sum_{i=1}^n\operatorname{fib}(i)f(i-2)+\operatorname{fib}^3(i)\right)+\sum_{i=1}^n\operatorname{fib}^2(i)\\&= \operatorname{fib}^2(n)\operatorname{fib}(n+1)+\operatorname{fib}(n)\operatorname{fib}(n+1) \end{aligned} \]

矩阵快速幂即可,代码:

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
using namespace std;
inline ll read(){
	ll x=0;char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
int t,md;
ll n,a,b,ans[3][3],l[3][3],d[3][3];
inline void mul(ll x[3][3],const ll y[3][3]){
    ll a=x[0][0],b=x[0][1],c=x[1][0],d=x[1][1];
    x[0][0]=(a*y[0][0]+b*y[1][0])%md;
    x[0][1]=(a*y[0][1]+b*y[1][1])%md;
    x[1][0]=(c*y[0][0]+d*y[1][0])%md;
    x[1][1]=(c*y[0][1]+d*y[1][1])%md;
}
inline void initd(){
	d[0][0]=0,d[0][1]=d[1][0]=d[1][1]=1;
}
void power(ll x){
    ans[0][0]=ans[1][1]=1;
    ans[0][1]=ans[1][0]=0;
    initd(); 
    for(;x;x>>=1){
        l[0][0]=d[0][0],l[0][1]=d[0][1];
        l[1][0]=d[1][0],l[1][1]=d[1][1];
        if(x&1)mul(ans,l);
        mul(d,l);
    }
}
signed main(){
	scanf("%d",&t);
	while(t--){
		n=read(),md=read();
		power(n-1);
		a=(ans[0][0]+ans[1][0])%md;
		b=(ans[0][1]+ans[1][1])%md;
		printf("%lld\n",(a*a+a)%md*b%md);
	}
	return 0;
}
posted @ 2023-06-27 18:00  zifanwang  阅读(6)  评论(0编辑  收藏  举报  来源