1 条题解
-
0
自动搬运
来自洛谷,原作者为

灯芯糕
草,赶紧先找个坑把自己埋了搬运于
2025-08-24 22:04:27,当前版本为作者最后更新于2018-09-01 13:59:52,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
矩阵乘法 + 快速幂优化递推:
看到这个题目我们不难想到递推,题干中说3个连续的A出现在序列中是不合法的,所以可以分为三种情况:
(1):序列前只有一个A,如:BA,BBA,BABA。
(2):序列前有两个A,如:BAA,BBAA,BABAA。
(3):序列前没有A而是B,如:BB,AB,AABAAB。
我们将这三种情况分别用 a1 , a2 , b 表示。
// a1:1 1 2 4 7 13 24 44 81 149 274 // a2:0 1 1 2 4 7 13 24 44 81 149 274 // b :1 2 4 7 13 24 44 81 149 274我们不难发现在下一轮加A或加B时:a1可以转化为a2,a1和a2都可以转化为b,而b又可以转化为a1或再加一个b不变;
故规律为:
// f=a2; // a2=a1; // a1=b; // b=(a1+a2+f)%19260817;注意变量会相互覆盖掉,f是借来存值的;
这是代码:
#include<iostream> using namespace std; int m,n,i,a1,a2,b1,f; int main(){ cin>>m; while(m--){ cin>>n; a1=1;b1=1;a2=0; for(i=2;i<=n;i++){ f=a2;a2=a1;a1=b1; b1=(a1+a2+f)%19260817; } cout<<(a1+a2+b1)%19260817<<endl; } return 0; }但是!
这题如果这么简单也就不会是蓝题了(其实上面那个代码也能拿80分的)。
我们知道一般递推复杂度为o(n),而这题数据范围中n<=(10^9),还可以问十次,绝对会超时的!
这里提供两种优化方案:
(1):
注:这是个打表的不正经的超有用的骗满分的暴力的方法:
测评姬只给你一秒时限,但你可以在自己电脑上算很久都没问题。
所以你可以在电脑上先算出从一开始每隔(10^7)位的三个递推数;当程序读入n时找到离n最近的递推数开始递推。
简单来说就是你可以在数组中先存下(10^8)的三个递推数a1,a2和b,这样就能直接从(10^8)开始递推到n;估计能比正解还快不少!
(2):
注:其实这里才进入主题,上面可以当做都是准备工作。
注:本蒟蒻也是今天才了解矩乘优化的QAQ,若有写的不好的地方各位大佬见谅。
我们先来了解一下矩阵:
矩阵就是一个二维方阵,矩阵A的第i行第j列可用A(i,j)来表示.
一个n行m列的矩阵A就是这样:
A(1,1) A(1,2) A(1,3) ... A(1,m)
A(2,1) A(2,2) A(2,3) ... A(2,m)
A(3,1) A(3,2) A(3,3) ... A(3,m)
...
A(n,1) A(n,2) A(n,3) ... A(n,m)
而矩阵乘法就是矩阵的一种运算
那么矩阵乘法的对象就是两个矩阵A和B,
注意:矩阵A的列数要与矩阵B的行数相等!
那么运算的答案矩阵C的第i行第j列即为:
C(i,j)=A(i,1)*B(1,j)+A(i,2)*B(2,j)+...+A(i,p)*B(p,j);
如下:
int jucheng(int n,int p,int m){ memset(c,0,sizeof(c)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)//p为矩阵A的列数与矩阵B的行数 for (int k=1;k<=p;k++) //枚举的所有递推数 c[i][j]+=a[i][k]*b[k][j] //公式 }矩阵乘法不满足交换律,但满足结合律.
AB!=BA
(AB)C=A(BC)
矩阵乘法也可以同余.
而当我们将矩阵乘法用到递推中时:
举一例:斐波那契数列:f[i]=f[i-1]+f[i-2].
把它用矩阵乘法表示:
// A(1,1) A(1,2) // [0 1]* =[1 1] // A矩阵 A(2,1) A(2,2) C矩阵 // B矩阵不难根据公示得出B矩阵为
0,1 1,1故递推矩阵为:
// 0 1 //[ f[i] f[i+1] ]* =[ f[i+1] f[i]+f[i+1] ]=[ f[i+1] f[i+2] ] // 1 1而本题中的递推矩阵为:
1,1,1 1,0,0 0,1,0本题大意就是要将此矩阵反复乘n次。这就可以用快速幂了!
下面现上代码:
#include<bits/stdc++.h> using namespace std; struct ju{ long long s[3][3]; }; ju cheng(ju a,ju b){//矩乘函数: ju c; for(int i=0;i<3;i++)for(int j=0;j<3;j++)c.s[i][j]=0; for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) c.s[i][j]+=a.s[i][k]*b.s[k][j],c.s[i][j]%=19260817; return c; } ju fast(int n){//快速幂: ju c,d; c.s[0][0]=c.s[0][1]=c.s[0][2]=c.s[1][0]=c.s[2][1]=1; c.s[1][1]=c.s[1][2]=c.s[2][0]=c.s[2][2]=0; if(n==1)return c;// d=fast(n/2);//这个很关键 if(n%2==0)return cheng(d,d); return cheng(cheng(d,d),c);//多了一个1要再多乘1次 } void print(ju n){// 输出: cout<<(n.s[0][0]+n.s[0][1])%19260817<<endl; } int main(){ int m,n; cin>>m; while(m--){//一个一个算: cin>>n; print(fast(n)); } return 0;//圆满 }码字挺累的(手残党,码了两小时了QAQ),大家点个赞再走吧。
- 1
信息
- ID
- 3772
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者