洛谷P5110 块速递推 题解

news/2024/12/5 3:25:50/

洛谷P5110 块速递推 题解

题目链接:P5110 块速递推

题意:给定一个数列 a a a 满足递推式
a 0 = 0 , a 1 = 1 a n = 233 a n − 1 + 666 a n − 2 a_0=0,a_1=1 \\a_n = 233a_{n-1}+666a_{n-2} a0=0,a1=1an=233an1+666an2
a n m o d ( 1 0 9 + 7 ) a_n \bmod (10^9+7) anmod(109+7)

多组询问

这个题是有个循环节的,正好是 1 0 9 + 6 10^9+6 109+6 ,据出题人说是凑好的

关于循环节怎么求的我也不太清楚,先留个坑,研究好了就补上来

也就是,如果数列 a n a_n an 在模 M M M 意义下存在循环节 p p p ,则有 a n ≡ a n m o d p m o d M a_n \equiv a_{n\,\bmod\, p} \bmod M ananmodpmodM

本题的解法就是手推通项公式

具体方法如下

对于二阶线性递推数列
a 0 = A , a 1 = B a n = p a n − 1 + q a n − 2 , n ≥ 2 a_0=A,a_1=B \\a_n = pa_{n-1}+qa_{n-2} ,n\ge 2 a0=A,a1=Ban=pan1+qan2,n2
考虑使用特征方程求解

a n = p a n − 1 + q a n − 2 a_n=pa_{n-1}+qa_{n-2} an=pan1+qan2 的特征方程为
x 2 = p x + q x^2=px+q x2=px+q
可以求出两个特解(不一定是实数) x 1 , x 2 x_1,x_2 x1,x2 ,则
a n = α x 1 n + β x 2 n a_n=\alpha x_1^{n} + \beta x_2^{n} an=αx1n+βx2n

注意,如果数列从 a 1 a_1 a1 开始,这里就是 a n = α x 1 n − 1 + β x 2 n − 1 a_n=\alpha x_1^{n-1} + \beta x_2^{n-1} an=αx1n1+βx2n1

然后将 a 0 = A , a 1 = B a_0=A,a_1=B a0=A,a1=B 代入可得
{ α + β = A α x 1 + β x 2 = B \begin{cases} \alpha + \beta = A \\\alpha x_1+\beta x_2=B \end{cases} {α+β=Aαx1+βx2=B
解出 α , β \alpha,\beta α,β 即可

本题的通项公式为
a n = 1 56953 ( ( 233 + 56953 2 ) n − ( 233 − 56953 2 ) n ) a_n=\dfrac{1}{\sqrt{56953}}\left(\left(\dfrac{233+\sqrt{56953}}{2}\right)^n-\left(\dfrac{233-\sqrt{56953}}{2}\right)^n\right) an=56953 1((2233+56953 )n(223356953 )n)
注意到这里有个 56953 \sqrt{56953} 56953 ,而我们要求它模意义下的值

也就是求出所有的 x x x
x 2 ≡ 56953 m o d ( 1 0 9 + 7 ) x^2\equiv 56953 \bmod(10^9+7) x256953mod(109+7)
考虑二次剩余求解

什么?不会二次剩余? 那么就打个暴力好了,最多几秒钟就跑出来了

#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{for(int i=1; i<=1000000000; i++)if(i*i%1000000007==56953)cout << i << endl;return 0;
}

然后有两个解 188305837 , 811694170 188305837,811694170 188305837,811694170 取个小点的代入就好了

则有
a n ≡ 233230706 × ( 9415303 5 n − 90584720 5 n ) a_n \equiv 233230706 \times(94153035^n-905847205^n) an233230706×(94153035n905847205n)
注意到询问有 1 0 7 10^7 107 个,快速幂过不了

考虑光速幂, O ( n ) O(\sqrt{n}) O(n ) 预处理 f ( x ) = x 65536 t , g ( x ) = x t f(x)=x^{65536t},g(x)=x^t f(x)=x65536t,g(x)=xt

询问直接查询 f ( x / 65536 ) × g ( n % 65536 ) f(x/65536)\times g(n\%65536) f(x/65536)×g(n%65536) 即可

这里可以用位运算加速

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace Mker
{unsigned long long SA,SB,SC;void init(){scanf("%llu%llu%llu",&SA,&SB,&SC);}unsigned long long rand(){SA^=SA<<32,SA^=SA>>13,SA^=SA<<1;unsigned long long t=SA;SA=SB,SB=SC,SC^=t^SA;return SC;}
}
#define N (int)(7e4+15)
const int p=(int)(1e9+7);
int Q;
uint ans;
uint pw1[2][N],pw2[2][N];
const int a=94153035;
const int b=905847205;
void init()
{pw1[0][0]=pw2[0][0]=1;for(int i=1; i<1<<16; i++)pw1[0][i]=pw1[0][i-1]*a%p;pw2[0][1]=pw1[0][(1<<16)-1]*a%p;for(int i=2; i<1<<16; i++)pw2[0][i]=pw2[0][i-1]*pw2[0][1]%p;pw1[1][0]=pw2[1][0]=1;for(int i=1; i<1<<16; i++)pw1[1][i]=pw1[1][i-1]*b%p;pw2[1][1]=pw1[1][(1<<16)-1]*b%p;for(int i=2; i<=1<<16; i++)pw2[1][i]=pw2[1][i-1]*pw2[1][1]%p;
}
int pow1(int n)
{return pw1[0][n&65535]%p*pw2[0][n>>16]%p;
}
int pow2(int n)
{return pw1[1][n&65535]%p*pw2[1][n>>16]%p;
}
uint solve(int n)
{return 233230706*(pow1(n)-pow2(n)+p)%p;
}
signed main()
{init();scanf("%lld",&Q);Mker::init();while(Q--)ans^=solve(Mker::rand()%(p-1));printf("%llu\n",ans);return 0;
}
//233230706×(94153035^n−905847205^n) 

转载请说明出处


http://www.ppmy.cn/news/306978.html

相关文章

【Arduino基础教程】LCD5110显示屏

Nokia 5110显示屏模块 准备材料 Arduino UNO *1Nokia 5110 LCD *1跳线 若干 接线 Nokia 5110显示屏接线示意图 Nokia 5110ArduinoRST->6CE->7DC->5DIN->4CLK->3VCC->5VBL->3V3GND->GND 加载库文件 到http://www.rinkydinkelectronics.com/download.php…

使用fill_n算法

今天使用这个算法来给一个数组赋值&#xff0c;所以把它的使用过程记录下来&#xff1a; fill_n函数的作用是&#xff1a;给你一个起始点&#xff0c;然后再给你一个数值count和val。把从起始点开始依次赋予count个元素val的值。 注意&#xff1a; 不能在没有元素的空容器上调…

Nokia 5110字模提取

字模提取其实就是通过描点来显示字符.如图所示。利用一个字节来描述8个像素的状态&#xff0c;依次排列&#xff0c;形成字符。 大致流程为&#xff1a; 阅读LCD描点方式&#xff0c;确定字模欺提取方式。主要包括LCD描点方向、高低位顺序 上图为Nokia的描点方式&#xff0c…

BZOJ 5110 [CodePlus2017]Yazid 的新生舞会 O(n)

题面 题解: 枚举每个数作为众数,枚举到的数赋为1,其它数赋为-1. 走一次统计一次肯定不现实,考虑动态更新走到当前点的答案res. 设sum为当前前缀和,f[i]表示前缀和为i的点有f[i]个,res即为所有小于sum的f[i]的和. 若接下去有一连串-1使得sum小于最小值,则一步跳到这串-1的末…

nokia游戏HTML5小游戏,用arduino做贪吃蛇小游戏,用Nokia5110的显示屏,Joystick Shieled......

程序代码是这样的&#xff1a;添加了库文件的 #include extern byte X_MAX82; extern byte Y_MAX46; extern unsigned char TinyFont[]; extern unsigned char SmallFont[]; byte DotX,DotY; byte SnakeBody[100][2]{{10,16},{10,18},{10,20}}; byte EatSelf0; byte NewFood…

dell 灵越N5110 拆机

参考&#xff1a; http://bbs.zol.com.cn/nbbbs/d21_3285.html

百超激光 镭射 bysoft6.8.1软件

百超激光 镭射 bysoft6.8.1软件 百超 激光 镭射 by soft 6.81 https://item.taobao.com/item.htm?spma1z10.1-c.w4004-5741239872.7.mKqRbP&id45110989365 转载于:https://www.cnblogs.com/daivyny/p/4952565.html

迷你世界滑动方块机器人怎么做_迷你世界:大神造出行走机器人,10秒可走100米,镭射激光辣眼!...

玩迷你世界的小伙伴都知道&#xff0c;在游戏中可以使用道具建造出自己喜欢的房屋、陷阱、建筑物等等有趣的东西&#xff0c;可是玩家们都知道静态得到东西比较容易造出&#xff0c;但是循环移动的东西就需要建造技术了&#xff0c;近日一位迷你世界的大神使用背包里的道具建造…