wanxue

博客园 首页 新随笔 联系 订阅 管理

题目解释

现有一数列:\(a_{0}=-3,a_{1}=-6,a_{2}=-12,a_{n}=3a_{n-1}+a_{n-2}-3a_{n-3}+3^n,求T组a_{n}\)mod p 的异或和

题目思路分析

抛开复杂度不谈,这道题可以用矩阵加速(矩阵的快速幂)和通项公式两种方法来做,这两种方法求一个\(a_{n}\)的时间复杂度都是\(log_2(n)\),但矩阵乘法需要更多时间,因此常数略大

总时间复杂度:

矩阵加速:O(\(16Tlog_2n\))
通项公式:O(\(Tlog_2n\))
而本题的T最大范围为[1,5e7],而n的最大可到\(2^{63}-1\),很显然,总时间复杂度的需求为O(n),尽管上述两种做法用快速幂实现都会TLE,但通项公式中的幂的底数固定,可以用光速幂预处理
因此整体思路为:先推通项公式,再用光速幂优化查询

通项公式推导

\(a_{n}=3a_{n-1}+a_{n-2}-3a_{n-3}+3^n\)
\(a_{n}-a_{n-2}=3(a_{n-1}-a_{n-3})+3^n\)
\(设a_{n}-a_{n-2}=b_{n} 得b_{2}=-9\)
\(b_{n}=3b_{n-1}+3^n\)
\(\frac{b_{n}}{3^n}=\frac{b_{n-1}}{3^n-1}+1\)
\(设\frac{b_{n}}{3^n}=c_{n} 得c_{2}=-1\)
\(c_{n}=c_{n-1}+1\)
\(c_{n}=c_{0}+n=c_{2}+n-2=-1+n-2=n-3\)
\(b_{n}=(n-3)3^n\)
\(a_{n}-a_{n-2}=(n-3)3^n\)
\(当n为偶数时 a_{n}=a_{0}+\sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i} =-3+\sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i}\)

\(设\sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i}=X\)

\(9X=9sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i}=sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i+2}\)

\(8X=9X-X=sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i+2}-sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i}\)

\(8X=(n-3)3^{(n+2)}+sum_{i=1}^{\frac{n}{2}-1} (2i-3)3^{2i+2}-sum_{i=2}^{\frac{n}{2}} (2i-3)3^{2i}+9\)

\(8X=(n-3)3^{(n+2)}-sum_{i=2}^{\frac{n}{2}} (2i-3-[2(i-1)-3])3^{2i}+9\)

\(8X=(n-3)3^{(n+2)}-sum_{i=2}^{\frac{n}{2}} 2*3^{2i}+9\)

\(8X=(n-3)3^{(n+2)}-\frac{3^(n+2)-3^4}{8}+9\)

\(X=\frac{(4n-13)3^{(n+2)}+117}{32}\)

\(a_{n}=\frac{(4n-13)3^{(n+2)}+117}{32}-3=\frac{(36n-117)3^n+21}{32}\)

\(当n为奇数时 a_{n}=a_{1}+\sum_{i=1}^{\frac{n}{2}} (2i-3)3^{2i}\)

同理\(a_{n}=\frac{(4n-13)3^{(n+2)}+51}{32}=\frac{(36n-117)3^{n}+51}{32}\)

代码实现

由于通项中所有幂的底数均为3,因此可以用光速幂预处理
其实现原理为\(a^{n}=a^{kx+y}=a^{kx}a^y\),分别预处理\(a^{kx}\)\(a^y\)
具体实施如下

#define Q 32000
//预处理
gsm1[0]=gsm2[0]=1;
for(int i=1;i<=Q;i++)gsm1[i]=1ll*gsm1[i-1]*3%mod;
for(int i=1;i<=Q;i++)gsm2[i]=1ll*gsm2[i-1]*gsm1[Q]%mod;
//调用
int gsm(int n){
	return 1ll*gsm2[n/Q]*gsm1[n%Q]%mod;
} 

由于答案需要取模,除以一个数需改为乘以它的逆元,所以我们可以通过快速幂计算得32在1e9+7下的逆元为281250002(即\(32^{1e9+5} mod 1e9+7\)
而由于有时n过大,我们可以利用\(a^n≡a^{(n-1)mod{p}}(mod{p}))\)来化简
最后,计算时记得乘上1ll,每算一次都要取一次模防止超出long long的范围

AC代码

#include<bits/stdc++.h>
#define mod 1000000007
#define _32 281250002
#define Q 32000
using namespace std;
int gsm1[Q+1],gsm2[Q+1],rst,T;
int gsm(int n){
	return 1ll*gsm2[n/Q]*gsm1[n%Q]%mod;
} 
namespace Mker
{
//  Powered By Kawashiro_Nitori
//  Made In Gensokyo, Nihon
	#include<climits>
	#define ull unsigned long long
	#define uint unsigned int
	ull sd;int op;
	inline void init() {scanf("%llu %d", &sd, &op);}
	inline ull ull_rand()
	{
		sd ^= sd << 43;
		sd ^= sd >> 29;
		sd ^= sd << 34;
		return sd;
	}
	inline ull rand()
	{
		if (op == 0) return ull_rand() % USHRT_MAX + 1;
		if (op == 1) return ull_rand() % UINT_MAX + 1; 
		if (op == 2) return ull_rand();
	}
}
int comput(unsigned long long x){
	if(x&1)return 1ll*(1ll*(36*(x%mod)-117+mod)%mod*gsm(x%(mod-1))+51)%mod*_32%mod;
	return 1ll*(1ll*(36*(x%mod)-117+mod)%mod*gsm(x%(mod-1))+21)%mod*_32%mod;
}
int main(){
	scanf("%d",&T);
	Mker::init();
	gsm1[0]=gsm2[0]=1;
	for(int i=1;i<=Q;i++)gsm1[i]=1ll*gsm1[i-1]*3%mod;
	for(int i=1;i<=Q;i++)gsm2[i]=1ll*gsm2[i-1]*gsm1[Q]%mod;
	while(T--){
		rst^=comput(Mker::rand());
	}
	printf("%d",rst);
}
posted on 2024-07-05 15:18  thelatersnow  阅读(25)  评论(0编辑  收藏  举报