题意
存在一个数列
{an}(n∈{0,1,2,⋯,1018⋯}) 。
已知
a0=−3,a1=−6,a2=−12,an=3an−1+an−2−3an−3+3n 。
- 现在给你给定的 n ,令 p=109+7 ,请你求出 anmodp 。
Solutions
Sol 1
Sol 2
直接暴力递推,时间复杂度
O(tn) ,期望得分:
20 pts 。
Sol 3
考虑将递推式转化为矩阵乘法:
⎣⎢⎢⎡ai−1ai−2ai−33i⎦⎥⎥⎤×⎣⎢⎢⎡31001010−30001003⎦⎥⎥⎤=⎣⎢⎢⎡aiai−1ai−23i+1⎦⎥⎥⎤
因为矩阵满足结合律,快速幂即可,时间复杂度
O(43×tlogn)
- 加上对于数据点12的打表,期望得分: 20−60 pts
Sol 4
由题目名字得知这是一个数学题。
构造关于
x 的OGF:
f(x)=a0x0+a1x1+a2x2+a3x3+⋯+anxn+⋯ ,
那么可以得到:
(3x3−x2−3x+1)f(x)=a0x0+(a1−3a0)x1+(a2−3a1−a0)x2+33x3+⋯+3nxn+⋯
将
a0=−3,a1=−6,a2=−12 代入后得:
(3x3−x2−3x+1)f(x)=−3+31x1+32x2+33x3+⋯+3nxn+⋯
因式分解后得到:
(3x−1)(x+1)(x−1)f(x)=−3+31x1+32x2+33x3+⋯+3nxn+⋯
用等比数列求和公式化简:
(3x−1)(x+1)(x−1)f(x)=−4+1−3x1=1−3x12x−3f(x)=(1−3x)2(1+x)(1−x)12x−3
用待定系数法把这个式子拆开:
(1−3x)2(1+x)(1−x)12x−3=(1−3x)2A+1+xB+1−xC+1−3xDA=(1+x)(1−x)12x−3∣∣∣∣∣x=31=89B=(1−3x)2(1−x)12x−3∣∣∣∣∣x=−1=−3215C=(1−3x)2(1+x)12x−3∣∣∣∣∣x=1=89
D单独求:
∵(1−3x)2(1+x)(1−x)(12x−3)x=(1−3x)2Ax+1+xBx+1−xCx+1−3xDx∴x→∞lim(xf(x))=0∴x→∞lim(B−C−31D)=0∴D=3×(B−C)=−32153
将求得的
A ,
B ,
C ,
D 代入
f(x) 中:
∵A=89,B=−3215,C=89,D=−32153∴f(x)=8(1−3x)29−32(1+x)15+8(1−x)9−32(1−3x)153∴f(x)=89i=0∑∞xi−3215i=0∑∞(−1)ixi−32153i=0∑∞3ixi+89i=0∑∞3ixi(i+1)∴f(x)=321i=0∑∞[3i+2×(4i−13)+36−15×(−1)i]xi∴an=323n+2×(4n−13)+36−15×(−1)n
快速幂即可,时间复杂度
O(tlogn) ,期望得分
30−60 pts 。
Sol 5
分析算法后发现,Sol 3因为常数巨大而不够优秀,然而Sol 4已经足够优秀却仍然超时。
发现
Sol 4中最烧时间的就是求
3n+2modp 的部分。
欧拉定理
因为
ab≡abmodφ(p)(modp) ,我们把时间复杂度成功地优化到了
O(tlogp) 。
考虑继续优化求
3pmodp 的部分。
"光速"幂
已知
p=109+7 ,
log2p≤32 。所以我们预处理出
216 以内的所有快速幂情况,每一次快速幂就可以
O(1) 完成了!
分析后我们的算法时间复杂度为
O(2×216+2t) ,空间复杂度为
O(216) ,期望得分:
80−100 pts 。
仍然不够优秀,考虑常数优化,如:
- 合理使用
long long
来减少取模的常数。
- 使用循环展开来降低常数。
- 使用
inline
,register
等常见的优化常数的技巧。
以上是std使用的优化方法,下面是一些神奇的优化方法(出题人没试过):
- 修改
Mker
中常数大的地方来减少常数。
- 更多的编译优化
&指令集?
- 在代码里注入
czakioi
等玄学的信仰优化
Code
#include<bits/stdc++.h>
using namespace std;
namespace Mker
{
#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();
}
}
#define re register int
#define ll long long
#define ull unsigned long long
#define in inline
const int base=16,lim=(1<<16)-1,inv32=281250002;
const ll p=1e9+7,pp=p*p;
int t,pre,ans,mul[2][lim+1];
ll m;
in ll multi(re a) {ll b=mul[0][a&lim];a>>=base;if(a)b=b*mul[1][a&lim]%p;return b;}
in void get_multi()
{
mul[0][0]=mul[1][0]=1;mul[0][1]=3;
for(re j=2;j<=lim;j++) mul[0][j]=1ll*mul[0][1]*mul[0][j-1]%p;
mul[1][1]=1ll*mul[0][lim]*mul[0][1]%p;
for(re j=2;j<=lim;j++) mul[1][j]=1ll*mul[1][1]*mul[1][j-1]%p;
}
int main()
{
scanf("%d",&t);Mker::init();get_multi();
while(t--)
{
ull n=Mker::rand();
pre=(n&1)?51:21;m=((n%p)<<2)-13+p;
ans^=(((multi((n+2)%(p-1))*m)%p+pre)*inv32+pp)%p;
}
printf("%d",ans);
return 0;
}
评论
发表评论