【bzoj3240 && 洛谷P1397】矩阵游戏[NOI2013](矩阵乘法+卡常)
题目传送门: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后终于卡进了时限。。。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define base 1000000000000000000ll
#define eps 1e-18
inline ll read()
{
ll tmp=; char c=getchar(),f=;
for(;c<''||''<c;c=getchar())if(c=='-')f=-;
for(;''<=c&&c<='';c=getchar())tmp=tmp*+c-'';
return tmp*f;
}
using namespace std;
struct mat{
ll num[][];
}mat1,mat2;
struct hp{
ll num[];
int len;
}n,m;
char s[],t[];
ll a,b,c,d;
mat times(mat a,mat b)
{
mat c;
c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
c.num[][]=(a.num[][]*b.num[][]+a.num[][]*b.num[][])%mod;
return c;
}
mat power_num(mat a,ll b)
{
mat ans; ans.num[][]=ans.num[][]=; ans.num[][]=ans.num[][]=;
while(b){
if(b&)ans=times(ans,a);
a=times(a,a); b>>=;
}
return ans;
}
mat power(mat a,hp b)
{
mat ans; ans.num[][]=ans.num[][]=; ans.num[][]=ans.num[][]=;
for(register int i=;i<=b.len;i++){
ans=times(ans,power_num(a,b.num[i]));
a=power_num(a,base);
}
return ans;
}
int main()
{
register int i;
scanf("%s",s); scanf("%s",t); a=read(); b=read(); c=read(); d=read();
mat1.num[][]=a; mat1.num[][]=b; mat1.num[][]=; mat1.num[][]=;
mat2.num[][]=c; mat2.num[][]=d; mat2.num[][]=; mat2.num[][]=;
int len1=strlen(s),len2=strlen(t);
for(i=;i*<=len1;i++){
n.num[i]=;
for(register short j=;j;j--)
n.num[i]=n.num[i]*+s[len1-(i-)*-j]-'';
}
n.len=len1/;
if(len1%){
n.num[++n.len]=;
for(register short j=;j<len1%;j++)n.num[n.len]=n.num[n.len]*+s[j]-'';
}
for(i=;i*<=len2;i++){
m.num[i]=;
for(register short j=;j;j--)
m.num[i]=m.num[i]*+t[len2-(i-)*-j]-'';
}
m.len=len2/;
if(len1%){
m.num[++m.len]=;
for(register short j=;j<len2%;j++)m.num[m.len]=m.num[m.len]*+t[j]-'';
}
n.num[]-=;
for(i=;i<=n.len;i++)if(n.num[i]<)n.num[i]+=base,n.num[i+]-=;
if(n.num[n.len]==&&n.len>)--n.len;
m.num[]-=;
for(i=;i<=m.len;i++)if(m.num[i]<)m.num[i]+=base,m.num[i+]-=;
if(m.num[m.len]==&&m.len>)--m.len;
mat hang=power(mat1,m);
mat ans=times(power(times(hang,mat2),n),hang);
printf("%lld\n",(ans.num[][]+ans.num[][])%mod);
}
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}$就好求了。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-18
inline ll read()
{
ll tmp=; char c=getchar(),f=;
for(;c<''||''<c;c=getchar())if(c=='-')f=-;
for(;''<=c&&c<='';c=getchar())tmp=(tmp<<)+(tmp<<)+c-'';
return tmp*f;
}
using namespace std;
char s[],t[];
ll a,b,c,d,n,m;
ll power(ll a,ll b)
{
ll ans=;
while(b){
if(b&)ans=ans*a%mod;
a=a*a%mod; b>>=;
}
return ans;
}
int main()
{
int i;
scanf("%s",s); scanf("%s",t); a=read(); b=read(); c=read(); d=read();
int len1=strlen(s),len2=strlen(t);
m=;
for(i=;i<len2;i++)m=(m*+t[i]-'')%(a>?mod-:mod);
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;
for(i=;i<len1;i++)n=(n*+s[i]-'')%(p>?mod-:mod);
ll ans=(power(p,n)+(p>?(power(p,n)+mod-)*power(p+mod-,mod-)%mod:n)*q)%mod;
printf("%lld\n",(ans+mod-d)*power(c,mod-)%mod);
}
bzoj3240
【bzoj3240 && 洛谷P1397】矩阵游戏[NOI2013](矩阵乘法+卡常)的更多相关文章
- 【题解】洛谷P1120 小木棍(搜索+剪枝+卡常)
洛谷P1120:https://www.luogu.org/problemnew/show/P1120 思路 明显是搜索题嘛 但是这数据增强不是一星半点呐 我们需要N多的剪枝 PS:需要先删去超出50 ...
- 洛谷P1129 【ZJOI2007】矩阵游戏
原题传送门 题目描述 小QQ是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个N \times NN×N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每 ...
- 洛谷 P2197 nim游戏
洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...
- 洛谷 P1965 转圈游戏
洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ...
- FFT/NTT总结+洛谷P3803 【模板】多项式乘法(FFT)(FFT/NTT)
前言 众所周知,这两个东西都是用来算多项式乘法的. 对于这种常人思维难以理解的东西,就少些理解,多背板子吧! 因此只总结一下思路和代码,什么概念和推式子就靠巨佬们吧 推荐自为风月马前卒巨佬的概念和定理 ...
- 洛谷P3758/BZOJ4887 [TJOI2017] 可乐 [矩阵快速幂]
洛谷传送门,BZOJ传送门 可乐 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 299 Solved: 207 Description 加里敦星球的人 ...
- 洛谷P3216 [HNOI2011] 数学作业 [矩阵加速,数论]
题目传送门 数学作业 题目描述 小 C 数学成绩优异,于是老师给小 C 留了一道非常难的数学作业题: 给定正整数 N和 M,要求计算 Concatenate (1 .. N)Mod M 的值,其中 C ...
- 洛谷 P1000 超级玛丽游戏
P1000 超级玛丽游戏 题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级 ...
- 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山
前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...
随机推荐
- 1、easyUI-创建 CRUD普通dataGrid(表格)
在实现功能之前,我们要做以下几个准备: 分以下几个步骤:开发工具,easyUI包,目录结构,创建数据库,创建相应的页面视图,后台代码编写,优化: 第一步:开发工具 我的开发工具是Hbuild,开发语言 ...
- css 变手
用css 添加手状样式,鼠标移上去变小手,变小手 用css 添加手状样式,鼠标移上去变小手,变小手 cursor:pointer; 用JS使鼠标变小手onmouseover(鼠标越过的时候) onmo ...
- std::condition_variable(复习)
#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> ...
- 【BZOJ2034】[2009国家集训队]最大收益 贪心优化最优匹配
[BZOJ2034][2009国家集训队]最大收益 Description 给出N件单位时间任务,对于第i件任务,如果要完成该任务,需要占用[Si, Ti]间的某个时刻,且完成后会有Vi的收益.求最大 ...
- 【BZOJ2819】Nim 树状数组+LCA
[BZOJ2819]Nim Description 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可 ...
- Java中Jedis操作Redis与Spring的整合
Redis是一个key-value存储系统.它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些数据类型都支持push/pop. ...
- pycharm 调试django 服务端断点调试
django runserver 服务端断电调试 D:\model\gitlab\eebo.ehr.analysis\venv\Scripts\python.exe "C:\Program ...
- CSS3选择器:nth-child与:nth-of-type区别
一.:nth-child 1.1 说明 :nth-child(n)选择器匹配属于其父元素的第N个子元素,不论元素的类型.n可以是数字.关键词或公式. 注意:如果第N个子元素与选择的元素类型不同则样式无 ...
- MySQL中B+树索引的使用
1) 不同应用中B+树索引的使用 对于OLTP应用,由于数据量获取可能是其中一小部分,建立B+树索引是有异议时的 对OLAP应用,情况比较复杂,因为索引的添加应该是宏观的而不是微观的. ...
- Python编码规范 -- Python Style Guide
Python代码风格规范. @1:参数缩进:(2种形式) <1> foo = long_function_name(var1, var2, var3, var4) #第1行有参数, 第2行 ...