[NOI2013]矩阵游戏
[NOI2013]矩阵游戏
此题解法大约两种,矩阵乘法和推式子
都说一下
矩阵乘法
构造一下矩阵
把\(\begin{bmatrix}a & 0 \\b & 1\end{bmatrix}\)称为\(A\),\(\begin{bmatrix}c & 0 \\d & 1\end{bmatrix}\)称作\(B\)
答案就是\(\begin{bmatrix}1 & 1 \\0 & 0\end{bmatrix}\times A^{n(m-1)}\times B^{n-1}\)这个矩阵的左上角元素
搭配十进制快速幂可获得80~100不等的分数
然后一些dalao发现元素会有循环,若a=1,循环节为1e9+7,否则为1e9+6
循环节在每行,每列都会循环,所以n,m取模即可
妥妥的AC
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
#define int long long
#define mod 1000000007
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
struct yyb{
int a,b,c,d;
yyb(int _a=1,int _b=0,int _c=0,int _d=1){a=_a%mod,b=_b%mod,c=_c%mod,d=_d%mod;}
};
yyb operator *(const yyb&a,const yyb&b){
return (yyb){
a.a*b.a+a.b*b.c, a.a*b.b+a.b*b.d,
a.c*b.a+a.d*b.c, a.c*b.b+a.d*b.d
};
}
char N[1000100],M[1000100];
int a,b,c,d,lenn,lenm,n,m;
yyb operator ^(yyb a,int b){
yyb ret;
while(b){
if(b&1)ret=ret*a;
a=a*a;b>>=1;
}
return ret;
}
main(){
scanf("%s%s%lld%lld%lld%lld",N+1,M+1,&a,&b,&c,&d);
lenn=strlen(N+1),lenm=strlen(M+1);
if(a!=1){
for(rg int i=1;N[i];++i)n=(n*10+N[i]-'0')%(mod-1);
for(rg int i=1;M[i];++i)m=(m*10+M[i]-'0')%(mod-1);
if(!n)n=mod-1;if(!m)m=mod-1;
}else{
for(rg int i=1;N[i];++i)n=(n*10+N[i]-'0')%mod;
for(rg int i=1;M[i];++i)m=(m*10+M[i]-'0')%mod;
if(!n)n=mod;if(!m)m=mod;
}
yyb S=(yyb){1,1,0,0},A=(yyb){a,0,b,1},B=(yyb){c,0,d,1};
A=(((A^(m-1))*B)^(n-1))*(A^(m-1));
printf("%lld\n",(S*A).a);
return 0;
}
暴力推式子
考虑从\(F[i][1]\)到\(F[i+1][1]\)的变化。
这个和随稽数生成器那题有点像(那道题保证互质就能用这个方法AC了)
\(a \ne 1:\)
\(F[i][m]=a^{m-1}F[i][1]+b(a^0+a^1+\cdot\cdot\cdot+a^{m-2})=a^{m-1}F[i][1]+b\times\frac{a^{m-1}}{a-1}\)
\(F[i+1][1]=a^{m-1}\times c\times F[i][1]+b\times c\times\frac{a^{m-1}}{a-1}+d\)
令\(p=a^{m-1}\times c,q=b\times c\times\frac{a^{m-1}}{a-1}+d\)
可以发现\(F[i+1][1]=p\times F[i][1]+q\)
\(a = 1:\)
\(F[i][m]=F[i][1]+b(m-1)\)
\(F[i+1][1]=c\times F[i][1]+b(m-1)\times c+d\)
这时的\(p=c,q=b(m-1)\times c+d\)
再按上述方法推一次可算出\(F[n+1][1]\)
减d除c即可得到答案
n和m好像也可以按矩阵的方法取模。。然后蜜汁85
贴上吧:
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define il inline
#define rg register
#define vd void
#define sta static
#define int long long
#define mod 1000000007
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
il int pow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}
return ret;
}
char nn[1000001],mm[1000001];
int n,m,a,b,c,d;
main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
scanf("%s%s",nn+1,mm+1);
for(rg int i=1;nn[i];++i)n=(n*10+nn[i]-'0')%(mod-1);
for(rg int i=1;mm[i];++i)m=(m*10+mm[i]-'0')%(mod-1);
a=gi(),b=gi(),c=gi(),d=gi();
int A,B,ans;
if(a==1)A=c,B=(b*c%mod*(m-1)%mod+d)%mod;
else{
int p=pow(a,m-1);
A=p*c%mod,B=(b*c%mod*(p-1)%mod*pow(a-1,mod-2)%mod+d)%mod;
}
if(A==1)ans=(1+B*n)%mod;
else{
int p=pow(A,n);
ans=(p+B*(p-1)%mod*pow(A-1,mod-2)%mod)%mod;
}
printf("%lld\n",(ans-d+mod)%mod*pow(c,mod-2)%mod);
return 0;
}
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。