题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3240

  这道题其实有普通快速幂+费马小定理的解法……然而我太弱了,一开始只想到了矩阵乘法的方法。

  首先定义两个矩阵:

  $ A_{1} = \begin{bmatrix} a & b \\ 0 & 1 \end{bmatrix} $
  $ A_{2} = \begin{bmatrix} c & d \\ 0 & 1 \end{bmatrix} $

  于是我们就可以得到这样的式子:

  $ \begin{aligned}  \begin{bmatrix} f_{n,m} \\ 1 \end{bmatrix} & = A_{1} \begin{bmatrix} f_{n,m-1} \\ 1 \end{bmatrix} \\ & = A_{1}^{m-1} \begin{bmatrix} f_{n,1} \\ 1 \end{bmatrix} \\ & = A_{1}^{m-1} A_{2}\begin{bmatrix} f_{n-1,m} \\ 1 \end{bmatrix} \\ & = ( A_{1}^{m-1}  A_{2} )^{n-1} \begin{bmatrix} f_{1,m} \\ 1 \end{bmatrix} \\ & = ( A_{1}^{m-1} A_{2} )^{n-1}  A_{1}^{m-1} \begin{bmatrix} f_{1,1} \\ 1 \end{bmatrix}  \end{aligned} $

  然后用一发10进制矩阵快速幂能解决这道题了。

  然而……这种做法跑的极慢。在洛谷上还能以近2000msAC,放到bzoj的6元cpu上跑就有些力不从心了,,所以得卡常数。

  经过了十几次提交,使用了奥义·卡常数:10^18进制进制快速幂+循环展开+register后终于卡进了时限。。。

  代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<algorithm>
  7. #include<queue>
  8. #include<vector>
  9. #define ll long long
  10. #define max(a,b) (a>b?a:b)
  11. #define min(a,b) (a<b?a:b)
  12. #define inf 0x3f3f3f3f
  13. #define mod 1000000007
  14. #define base 1000000000000000000ll
  15. #define eps 1e-18
  16. inline ll read()
  17. {
  18. ll tmp=; char c=getchar(),f=;
  19. for(;c<''||''<c;c=getchar())if(c=='-')f=-;
  20. for(;''<=c&&c<='';c=getchar())tmp=tmp*+c-'';
  21. return tmp*f;
  22. }
  23. using namespace std;
  24. struct mat{
  25. ll num[][];
  26. }mat1,mat2;
  27. struct hp{
  28. ll num[];
  29. int len;
  30. }n,m;
  31. char s[],t[];
  32. ll a,b,c,d;
  33. mat times(mat a,mat b)
  34. {
  35. mat c;
  36. c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
  37. c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
  38. c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
  39. c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
  40. return c;
  41. }
  42. mat power_num(mat a,ll b)
  43. {
  44. mat ans; ans.num[][]=ans.num[][]=; ans.num[][]=ans.num[][]=;
  45. while(b){
  46. if(b&)ans=times(ans,a);
  47. a=times(a,a); b>>=;
  48. }
  49. return ans;
  50. }
  51. mat power(mat a,hp b)
  52. {
  53. mat ans; ans.num[][]=ans.num[][]=; ans.num[][]=ans.num[][]=;
  54. for(register int i=;i<=b.len;i++){
  55. ans=times(ans,power_num(a,b.num[i]));
  56. a=power_num(a,base);
  57. }
  58. return ans;
  59. }
  60. int main()
  61. {
  62. register int i;
  63. scanf("%s",s); scanf("%s",t); a=read(); b=read(); c=read(); d=read();
  64. mat1.num[][]=a; mat1.num[][]=b; mat1.num[][]=; mat1.num[][]=;
  65. mat2.num[][]=c; mat2.num[][]=d; mat2.num[][]=; mat2.num[][]=;
  66. int len1=strlen(s),len2=strlen(t);
  67. for(i=;i*<=len1;i++){
  68. n.num[i]=;
  69. for(register short j=;j;j--)
  70. n.num[i]=n.num[i]*+s[len1-(i-)*-j]-'';
  71. }
  72. n.len=len1/;
  73. if(len1%){
  74. n.num[++n.len]=;
  75. for(register short j=;j<len1%;j++)n.num[n.len]=n.num[n.len]*+s[j]-'';
  76. }
  77. for(i=;i*<=len2;i++){
  78. m.num[i]=;
  79. for(register short j=;j;j--)
  80. m.num[i]=m.num[i]*+t[len2-(i-)*-j]-'';
  81. }
  82. m.len=len2/;
  83. if(len1%){
  84. m.num[++m.len]=;
  85. for(register short j=;j<len2%;j++)m.num[m.len]=m.num[m.len]*+t[j]-'';
  86. }
  87. n.num[]-=;
  88. for(i=;i<=n.len;i++)if(n.num[i]<)n.num[i]+=base,n.num[i+]-=;
  89. if(n.num[n.len]==&&n.len>)--n.len;
  90. m.num[]-=;
  91. for(i=;i<=m.len;i++)if(m.num[i]<)m.num[i]+=base,m.num[i+]-=;
  92. if(m.num[m.len]==&&m.len>)--m.len;
  93. mat hang=power(mat1,m);
  94. mat ans=times(power(times(hang,mat2),n),hang);
  95. printf("%lld\n",(ans.num[][]+ans.num[][])%mod);
  96. }

bzoj3240


解法2:

  我们可以发现把$f_{1,i}=af_{i-1}+b$不断地展开后就能得到$f_{1,i}=a^i f_{1,1}+b\sum_{k=0}^{i-1}a^{k}$,即$f_{2,1}=a^{i}cf_{1,1}+bc\sum_{k=0}^{m-1}a^{k}+d$,于是我们可以用等比数列求和公式化简这个式子,又因为1e9+7是质数,所以可以由费马小定理将指数对1e9+6取模(不过需特判$a=1$的情况)。

  然后我们可以发现这个式子也是$f_{i,1}=af_{i-1,1}+b$的形式(其中$ a,b $是常数),于是用上面的方法求出$f_{n+1,1}$,然后$f_{n,m}$就好求了。

代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<algorithm>
  7. #include<queue>
  8. #include<vector>
  9. #define ll long long
  10. #define max(a,b) (a>b?a:b)
  11. #define min(a,b) (a<b?a:b)
  12. #define inf 0x3f3f3f3f
  13. #define mod 1000000007
  14. #define eps 1e-18
  15. inline ll read()
  16. {
  17. ll tmp=; char c=getchar(),f=;
  18. for(;c<''||''<c;c=getchar())if(c=='-')f=-;
  19. for(;''<=c&&c<='';c=getchar())tmp=(tmp<<)+(tmp<<)+c-'';
  20. return tmp*f;
  21. }
  22. using namespace std;
  23. char s[],t[];
  24. ll a,b,c,d,n,m;
  25. ll power(ll a,ll b)
  26. {
  27. ll ans=;
  28. while(b){
  29. if(b&)ans=ans*a%mod;
  30. a=a*a%mod; b>>=;
  31. }
  32. return ans;
  33. }
  34. int main()
  35. {
  36. int i;
  37. scanf("%s",s); scanf("%s",t); a=read(); b=read(); c=read(); d=read();
  38. int len1=strlen(s),len2=strlen(t);
  39. m=;
  40. for(i=;i<len2;i++)m=(m*+t[i]-'')%(a>?mod-:mod);
  41. ll p=power(a,m-)*c%mod,q=((a>?(power(a,m-)+mod-)*power(a+mod-,mod-)%mod:m-)*b%mod*c%mod+d)%mod;
  42. for(i=;i<len1;i++)n=(n*+s[i]-'')%(p>?mod-:mod);
  43. ll ans=(power(p,n)+(p>?(power(p,n)+mod-)*power(p+mod-,mod-)%mod:n)*q)%mod;
  44. printf("%lld\n",(ans+mod-d)*power(c,mod-)%mod);
  45. }

bzoj3240

【bzoj3240 && 洛谷P1397】矩阵游戏[NOI2013](矩阵乘法+卡常)的更多相关文章

  1. 【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)

    洛谷P1120:https://www.luogu.org/problemnew/show/P1120 思路 明显是搜索题嘛 但是这数据增强不是一星半点呐 我们需要N多的剪枝 PS:需要先删去超出50 ...

  2. 洛谷P1129 【ZJOI2007】矩阵游戏

    原题传送门 题目描述 小QQ是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个N \times NN×N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每 ...

  3. 洛谷 P2197 nim游戏

    洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...

  4. 洛谷 P1965 转圈游戏

    洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ...

  5. FFT/NTT总结+洛谷P3803 【模板】多项式乘法(FFT)(FFT/NTT)

    前言 众所周知,这两个东西都是用来算多项式乘法的. 对于这种常人思维难以理解的东西,就少些理解,多背板子吧! 因此只总结一下思路和代码,什么概念和推式子就靠巨佬们吧 推荐自为风月马前卒巨佬的概念和定理 ...

  6. 洛谷P3758/BZOJ4887 [TJOI2017] 可乐 [矩阵快速幂]

    洛谷传送门,BZOJ传送门 可乐 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 299  Solved: 207 Description 加里敦星球的人 ...

  7. 洛谷P3216 [HNOI2011] 数学作业 [矩阵加速,数论]

    题目传送门 数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N和 M,要求计算 Concatenate (1 .. N)Mod M 的值,其中 C ...

  8. 洛谷 P1000 超级玛丽游戏

    P1000 超级玛丽游戏 题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级 ...

  9. 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山

    前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...

随机推荐

  1. Expression<Func<T, bool>>与Func<T, bool>的区别

    转自:http://www.cnblogs.com/wow-xc/articles/4952233.html Func<TObject, bool>是委托(delegate) Expres ...

  2. ScheduleFactory(不同scheduler name)

    package com.unis.uvm.quartz; import java.util.Properties; import org.quartz.Scheduler; import org.qu ...

  3. node.js的安装与第一个hello world、node.js的初始化

    1.下载node.js文件 2.windows下点击安装  重复下一步即可 3.编辑工具  EditPlus编辑器 4.新建保存目录的文件夹,并新建一个文本文档 5.打开EditPlus编辑器  打开 ...

  4. Android UI开发第二十九篇——Android中五种常用的menu(菜单)

    Android Menu在手机的应用中起着导航的作用,作者总结了5种常用的Menu. 1.左右推出的Menu 前段时间比较流行,我最早是在海豚浏览器中看到的,当时耳目一新.最早使用左右推出菜单的,听说 ...

  5. python学习【第十一篇】网络编程

    一.socket的简介 socket(简称:套接字)进程间通信的一种方式,它与其他进程间通信的一个主要不同是:能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通 ...

  6. SharePoint 离线安装

    SharePoint 离线安装,主要是AppFrabic服务出错,可以使用下来命令: "X:\WindowsServerAppFabricSetup_x64.exe" /i Cac ...

  7. 《从零开始学Swift》学习笔记(Day4)——用Playground工具编写Swift

    Swift 2.0学习笔记(Day4)——用Playground工具编写Swift 原创文章,欢迎转载.转载请注明:关东升的博客 用Playground编写Swift代码目的是为了学习.测试算法.验证 ...

  8. phpwind 论坛 转移

    前段时间用phpwind 搭建了一个本地论坛系统,也写过一篇随笔,讲phpwind论坛的迁移,昨天网上又对论坛做了迁移,在本地搭建了系统. 使用的是之前没有成功的方法.这种方法挺方便的,之前每次都是重 ...

  9. 如何将大数据保存到 MySql 数据库

    1. 什么是大数据 1. 所谓大数据, 就是大的字节数据,或大的字符数据. 2. 标准 SQL 中提供了如下类型来保存大数据类型: 字节数据类型: tinyblob(256B), blob(64K), ...

  10. 谷歌浏览器input中的text 和 button 水平对齐的问题

    方法一  text 的vertical-align :top; 方法二  button的vertical-align: middle;