The Nth Iteam

题意:F(0)=1,F(1)=1,F(n)=3*F(n-1)+2*F(n-2) (n>=2) ,F(n) mod 998244353。给出Q跟N1,Ni=Ni-1^(F(Ni-1)*F(Ni-1)),求F(N1)^F(N2)^...^F(NQ

这个比赛的E跟H数据都水得很,但题还是不错的。

比赛时是求了个循环节,又进行了矩阵的降幂,然后本地+测试在时限内跑出了几组1e7的数据,才敢交的,但没想到数据那么水,矩阵快速幂+map记忆化一下就能过。

  1. #include<cstdio>
  2. #include<tr1/unordered_map>
  3. using namespace std;
  4. typedef long long ll;
  5. const int N=1e7+,md=;
  6. tr1::unordered_map<ll,int> mmp;
  7. ll aa[N],f[N];
  8. struct Matrix{
  9. int r,c;
  10. ll a[][];
  11. Matrix(){}
  12. Matrix(int r,int c):r(r),c(c){
  13. for(int i=;i<r;i++)
  14. for(int j=;j<c;j++) a[i][j]=;
  15. }
  16. };
  17. Matrix mmul(Matrix m1,Matrix m2,ll z){
  18. Matrix ans(m1.r,m2.c);
  19. for(int i=;i<m1.r;i++)
  20. for(int j=;j<m2.c;j++)
  21. for(int k=;k<m1.c;k++){
  22. ans.a[i][j]+=m1.a[i][k]*m2.a[k][j]%z;
  23. if(ans.a[i][j]>=z) ans.a[i][j]-=z;
  24. }
  25. return ans;
  26. }
  27. Matrix mpow(Matrix m1,ll y,ll z){
  28. Matrix ans(m1.r,m1.c);
  29. for(int i=;i<ans.r;i++) ans.a[i][i]=;
  30. while(y){
  31. if(y&) ans=mmul(ans,m1,z);
  32. m1=mmul(m1,m1,z);
  33. y>>=;
  34. }
  35. return ans;
  36. }
  37.  
  38. int main(){
  39. f[]=;f[]=;
  40. for(int i=;i<N;i++) f[i]=(f[i-]*3ll%md+f[i-]*2ll%md)%md;
  41. int q,pos1,pos2,len,num,yu;
  42. ll n,m,ans;
  43. while(~scanf("%d%lld",&q,&n)){
  44. ans=aa[]=;
  45. mmp.clear();
  46. pos1=pos2=-;
  47. for(int i=;i<=q;i++){
  48. if(n<N) aa[i]=f[n];
  49. else{
  50. m=n-;
  51. if(m>=md-) m%=md-;
  52. Matrix A(,),T(,);
  53. A.a[][]=;
  54. T.a[][]=;T.a[][]=;T.a[][]=;
  55. T=mpow(T,m,md);
  56. A=mmul(T,A,md);
  57. aa[i]=A.a[][];
  58. }
  59. if(n==) break;
  60. if(mmp[n]){
  61. pos1=mmp[n];
  62. pos2=i;
  63. break;
  64. }
  65. else mmp[n]=i;
  66. ans^=aa[i];
  67. n=n^(aa[i]*aa[i]);
  68. aa[i]^=aa[i-];
  69. }
  70. if(pos1!=-){
  71. len=pos2-pos1;
  72. num=(q-pos2+)/len;
  73. yu=(q-pos2+)%len;
  74. if(num&) ans^=aa[pos2-]^aa[pos1-];
  75. if(yu) ans^=aa[pos1+yu-]^aa[pos1-];
  76. }
  77. printf("%lld\n",ans);
  78. }
  79. return ;
  80. }

不应该过呀

但其实自己想一下,Q等于1e7,中间再套log的话,还有算矩阵快速幂时的一些常数,很明显就会T掉,水过去之余还是来学一些O(1)的处理方法。

首先这个数列显然是个线性递推数列,那么我们就可以求它的一个通项公式,具体求法360百科有好几个,我直接学习了第一个,方法:利用特征方程(线性代数解法)的解法。

下面是斐波那契数列通项公式的求解过程,我们依照此来求:

特征方程的概述

一个数列:X(n+2)=C1X(n+1)+C2Xn

设r,s使X(n+2)-rX(n+1)=s[X(n+1)-rXn]

所以X(n+2)=(s+r)X(n+1)-srXn

C1=s+r

C2=-sr

消去s就导出特征方程式 r*r-C1*r-C2=0

我们把C1=3,C2=2代入就有可以解除r=(3+√17)/2,s=(3-√17)/2

然后F(n)=x1*rn+x2*sn,我们把F(0)=0,F(1)=1,代入就能解得x1=1/√17,x2=-1/√17

那么上诉数列的通项公式就是F(n)=1/√17*(((3+√17)/2)n-((3-√17)/2)n)

这个解法包含不少线性代数的知识,不明白的可以去学一下那个待定系数等比数列求法,或者看一下这个斐波那契数列通项公式是怎样推导出来的?,里面有矩阵的推导过程。

回到这题,我们有了通项公式,√17的话,前面的博客就有讲到二次剩余,那么通过x2≡17(mod 998244353)可以求出x来代替√17,然后里面的除法我们可以求逆元,这些都可以先求出了。

相关代码如下:

  1. #include<cstdio>
  2. #include<ctime>
  3. #include<cstdlib>
  4. #include<algorithm>
  5. using namespace std;
  6. const int md=;
  7. typedef long long ll;
  8. struct Fp2{
  9. ll x,y;
  10. };
  11. ll w;
  12. Fp2 fmul(const Fp2 &f1,const Fp2 &f2){
  13. Fp2 ans;
  14. ans.x=(f1.x*f2.x%md+f1.y*f2.y%md*w%md)%md;
  15. ans.y=(f1.x*f2.y%md+f1.y*f2.x%md)%md;
  16. return ans;
  17. }
  18. Fp2 fpow(Fp2 x,ll y){
  19. Fp2 ans;
  20. ans.x=;ans.y=;
  21. while(y){
  22. if(y&) ans=fmul(ans,x);
  23. x=fmul(x,x);
  24. y>>=;
  25. }
  26. return ans;
  27. }
  28. ll poww(ll x,ll y){
  29. ll ans=;
  30. while(y){
  31. if(y&){
  32. ans*=x;
  33. if(ans>=md) ans%=md;
  34. }
  35. x*=x;
  36. if(x>=md) x%=md;
  37. y>>=;
  38. }
  39. return ans;
  40. }
  41. ll cipolla(ll x){
  42. if(x==) return ;
  43. if(x==) return ;
  44. if(poww(x,(md-)>>)+==md) return -;
  45. ll a;
  46. while(true){
  47. a=rand()%md;
  48. w=((a*a%md-x)%md+md)%md;
  49. if(poww(w,(md-)>>)+==md) break;
  50. }
  51. Fp2 ans;
  52. ans.x=a;ans.y=;
  53. ans=fpow(ans,(md+)>>);
  54. return ans.x;
  55. }
  56. int main(){
  57. srand(time(NULL));
  58. ll py17=cipolla(),nv2=poww(,md-);
  59. printf("根号17的二次剩余:%lld\n",py17);
  60. printf("2的逆元:%lld\n",nv2);
  61. printf("根号17的二次剩余的逆元:%lld\n",poww(py17,md-));
  62. printf("3+根号7除2:%lld\n",((+py17)%md*nv2%md)%md);
  63. printf("3-根号7除2:%lld\n",(((-py17)%md+md)%md*nv2%md)%md);
  64. return ;
  65. }

打表鸭

其中一组结果:

那么这时,我们设aa=736044383,bb=262199973,我们快速幂就可以log求出F(n)

但这还不够,我们需要的是O(1),所以我们可以先分块预处理。

怎么做呢,这时的aa,bb在 mod 998244353的意义下,已经是整数了,所以求aan或者bbn在n很大时,就可以进行我们前面指数循环节里的欧拉降幂了,也就是n=n%998244352+998244352(998244352是998244353是欧拉函数)

这时n最大是1996488703,√1996488703=44682.084810357719028060186400879,那么我们可以把5e4(大于等于44683都可以)为一组分块,这样我们先预处理出aa跟bb的0次幂,1次幂,到5e4次幂,然后再预处理0*5e4次幂,1*5e4次幂到5e4*5e4次幂

那么当我们要求aa或者bb的n次幂时其实就是求(n/5e4)(整除)*5e4次幂 * n%5e4次幂,也就是设N=5e4,那么 n=q*N+r,q=n/N,r=n%N

这样我们就可以在O(1)求出相应的F(n),

  1. #include<cstdio>
  2. typedef long long ll;
  3. const int N=5e4,md=;
  4. const ll nv17=,aa=,bb=;
  5. typedef long long ll;
  6. ll a[N+],af[N+],b[N+],bf[N+];
  7. void init(){
  8. a[]=b[]=;
  9. for(int i=;i<=N;i++){
  10. a[i]=a[i-]*aa;
  11. if(a[i]>=md) a[i]%=md;
  12. b[i]=b[i-]*bb;
  13. if(b[i]>=md) b[i]%=md;
  14. }
  15. af[]=bf[]=;
  16. for(int i=;i<=N;i++){
  17. af[i]=af[i-]*a[N];
  18. if(af[i]>=md) af[i]%=md;
  19. bf[i]=bf[i-]*b[N];
  20. if(bf[i]>=md) bf[i]%=md;
  21. }
  22. }
  23. int main(){
  24. init();
  25. int q;
  26. ll n;
  27. while(~scanf("%d%lld",&q,&n)){
  28. ll ans=,fn,m;
  29. while(q--){
  30. if(n==) break;
  31. m=n;
  32. if(m>=md-) m=m%(md-)+(md-);
  33. fn=((af[m/N]*a[m%N])%md)-((bf[m/N]*b[m%N])%md);
  34. fn=(fn%md+md)%md;
  35. fn*=nv17;
  36. if(fn>=md) fn%=md;
  37. ans^=fn;
  38. n=n^(fn*fn);
  39. }
  40. printf("%lld\n",ans);
  41. }
  42. return ;
  43. }

嘤嘤嘤

但由于数据的问题,预处理在计蒜客上实际运行时间还没直接套矩阵快速幂的快,自己出几个大数据就可看出哪个更快了,但我们不要被数据影响了,学到东西才是关键了。

总的来说,这题涉及到了线性递推数列的通项公式,二次剩余,逆元,还有分块思想,是个很不错的题。

2019 南昌ICPC网络赛H The Nth Item的更多相关文章

  1. 南昌网络赛 H The Nth Item

    南昌网络赛The Nth Item 暴力快速幂+unordered_map记忆化 注意:记忆化不能写到快速幂求解函数里,不断调用函数会造成很大的时间浪费 #include<bits/stdc++ ...

  2. 2019南昌网络赛H The Nth Item(打表找询问循环节 or 分段打表)

    https://nanti.jisuanke.com/t/41355 思路 从fib循环节入手,\(O(1e7log(1e9))\),tle 因为只需要输出所有询问亦或后的结果,所以考虑答案的循环节, ...

  3. 2019南昌网络赛H The Nth Item(二阶线性数列递推 + 广义斐波那契循环节 + 分段打表)题解

    题意: 传送门 已知\(F(n)=3F(n-1)+2F(n-2) \mod 998244353,F(0)=0,F(1)=1\),给出初始的\(n_1\)和询问次数\(q\),设每一次的答案\(a_i= ...

  4. 2019沈阳icpc网络赛H德州扑克

    题面:https://nanti.jisuanke.com/t/41408 题意:A,2,3,4,5,6,7,8,9,10,J,Q,K,13张牌,无花色之分,val为1~13. 给n个人名+n个牌,输 ...

  5. 2019-ACM-ICPC-南昌区网络赛-H. The Nth Item-特征根法求通项公式+二次剩余+欧拉降幂

    2019-ACM-ICPC-南昌区网络赛-H. The Nth Item-特征根法求通项公式+二次剩余+欧拉降幂 [Problem Description] ​ 已知\(f(n)=3\cdot f(n ...

  6. POJ-2796 & 2019南昌邀请赛网络赛 I. 区间最大min*sum

    http://poj.org/problem?id=2796 https://nanti.jisuanke.com/t/38228 背景 给定一个序列,对于任意区间,min表示区间中最小的数,sum表 ...

  7. 计蒜客 2019南昌邀请网络赛J Distance on the tree(主席树)题解

    题意:给出一棵树,给出每条边的权值,现在给出m个询问,要你每次输出u~v的最短路径中,边权 <= k 的边有几条 思路:当时网络赛的时候没学过主席树,现在补上.先树上建主席树,然后把边权交给子节 ...

  8. 2019南昌邀请赛网络赛:J distance on the tree

    1000ms 262144K   DSM(Data Structure Master) once learned about tree when he was preparing for NOIP(N ...

  9. 2019 徐州icpc网络赛 E. XKC's basketball team

    题库链接: https://nanti.jisuanke.com/t/41387 题目大意 给定n个数,与一个数m,求ai右边最后一个至少比ai大m的数与这个数之间有多少个数 思路 对于每一个数,利用 ...

随机推荐

  1. C#字典转对象

    /// <summary> /// Assign parameters to specified objects /// </summary> /// <typepara ...

  2. 出现 HTTP 错误 500.19 错误代码 0x800700b7

    这个内容出现主要问题是在IIS上,我们一般程序开发 iis中默认的路径只是http://localhost/,相当于环境变量中已定义好了,如果自己创建的项目直接将路径定义到这,就会替换图二中的路径,然 ...

  3. 【原创】大叔经验分享(82)logstash一个实例运行多个配置文件

    logstash一个实例运行多个配置文件,将所有配置文件放到以下目录即可 /usr/share/logstash/pipeline 但是默认行为不是每个配置文件独立运行,而是作为一个整体,每个inpu ...

  4. Oracle对字段去重查询所有字段数据

    单个字段: select distinct(a) from tableA; 多个字段,利用max()去重  SELECT  * FROM  GM_PPU_RESIDENT_NORBASE g  WHE ...

  5. SSISDB8:查看SSISDB记录Package执行的消息

    在执行Package时,SSISDB都会创建唯一的OperationID 和 ExecutionID,标识对package执行的操作和执行实例(Execution Instance),并记录opera ...

  6. liunx加载JX2410标准配置文件

  7. JAVA中AES对称加密和解密以及与Python兼容

    引言:本文主要解决Java中用AES加密及解密,同时可通过Python脚本对Java加密后的字符进行解密的操作. 由于近期工作中用到需要使用Java对一串密钥进行加密,并且后台通过Python语言读取 ...

  8. Django ORM常用的字段和参数

    ORM 常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. IntegerField 一个整数类 ...

  9. mysql 5.6.38 数据库编译安装

    一.系统环境: # cat /etc/redhat-release CentOS release 6.9 (Final) 二.mysql 编译安装: 1.安装依赖包: yum install -y n ...

  10. springboot无法获取证书内容

    最近项目里面在接第三方验证的时候,需要用到生成的公钥和私钥证书.在demo测试的时候,发现在resources里面直接建立一个key文件夹放入证书文件,然后使用文件方式去获取,大概代码如下: File ...