(十进制快速幂+矩阵优化)BZOJ 3240 3240: [Noi2013]矩阵游戏
2014-04-24 14:57
561 查看
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=3240
Submit: 317 Solved: 152
[Submit][Status]
F[1][1]=1
F[i,j]=a*F[i][j-1]+b (j!=1)
F[i,1]=c*F[i-1][m]+d (i!=1)
递推式中a,b,c,d都是给定的常数。
现在婷婷想知道F
[m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F
[m]除以1,000,000,007的余数。
[m]除以1,000,000,007的余数
1 4 7 10
26 29 32 35
76 79 82 85
十进制快速幂
需要优化常数,可以把矩阵优化到只保存两个数,每次矩阵乘法时,只需计算两次乘法就行了,大大加快了速度。
显然最后结果为A^m(BA^mF)^n 其中A(a,b,0,1) B(c,d,0,1) F(1,0,0,1)
保存一个v1,v2. 矩阵乘法时 c.v1=a.v1*b.v1 c.v2=a.v1*b.v2+a.v2 (ta*(1,2)+tb=(ta*1,ta*2+tb))
代码:
解题思路:
可以暴力推出公式.费马小定理不适合于矩阵的次幂,a=c=1时,退化成等差数列,需特判,其余等比数列。这题这样做有问题。矩阵的次幂不能用费马小定理来降次,只是这题有点特殊。
代码:
http://www.lydsy.com/JudgeOnline/problem.php?id=3240
3240: [Noi2013]矩阵游戏
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 317 Solved: 152
[Submit][Status]
Description
婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储)。她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式:F[1][1]=1
F[i,j]=a*F[i][j-1]+b (j!=1)
F[i,1]=c*F[i-1][m]+d (i!=1)
递推式中a,b,c,d都是给定的常数。
现在婷婷想知道F
[m]的值是多少,请你帮助她。由于最终结果可能很大,你只需要输出F
[m]除以1,000,000,007的余数。
Input
一行有六个整数n,m,a,b,c,d。意义如题所述Output
包含一个整数,表示F[m]除以1,000,000,007的余数
Sample Input
3 4 1 3 2 6Sample Output
85HINT
样例中的矩阵为:1 4 7 10
26 29 32 35
76 79 82 85
Source
解题思路:十进制快速幂
需要优化常数,可以把矩阵优化到只保存两个数,每次矩阵乘法时,只需计算两次乘法就行了,大大加快了速度。
显然最后结果为A^m(BA^mF)^n 其中A(a,b,0,1) B(c,d,0,1) F(1,0,0,1)
保存一个v1,v2. 矩阵乘法时 c.v1=a.v1*b.v1 c.v2=a.v1*b.v2+a.v2 (ta*(1,2)+tb=(ta*1,ta*2+tb))
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) //#define ll __int64 #define ll long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define MM 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1100000 char s1[Maxn],s2[Maxn]; ll a,b,c,d; void sub(char * cur) { int len=strlen(cur); len--; if(cur[len]!='0') { cur[len]=cur[len]-1; return ; } cur[len]='9'; len--; while(len>=0&&cur[len]=='0') { cur[len]='9'; len--; } cur[len]=cur[len]-1; } struct Mar { ll v1,v2; void init(ll a,ll b) { v1=a; v2=b; } friend struct Mar operator * (const struct Mar &a,const struct Mar &b) { Mar c; c.v1=(a.v1*b.v1)%MM; c.v2=(a.v1*b.v2+a.v2)%MM; return c; } }; Mar Pow(Mar aa,ll bb) { Mar c; c.init(1,0); //c.s[1][1]=1,c.s[2][2]=1; while(bb) { if(bb&1) c=aa*c; bb>>=1; aa=aa*aa; } return c; } Mar T_Pow(Mar aa,char * cur) { Mar res; res.init(1,0); int i=strlen(cur)-1; int j=0; while(cur[j]=='0') j++; while(i>=j) { res=Pow(aa,cur[i]-'0')*res; aa=Pow(aa,10); i--; } return res; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(~scanf("%s%s",s1,s2)) { scanf("%lld%lld%lld%lld",&a,&b,&c,&d); sub(s1); //printf("%s\n",s1); sub(s2); //printf("%s\n",s2); // ll n=cal(s1),m=cal(s2); Mar A; A.init(a,b); //A.s[1][1]=a,A.s[1][2]=b,A.s[2][2]=1; Mar B; B.init(c,d); //B.s[1][1]=c,B.s[1][2]=d,B.s[2][2]=1; Mar C=T_Pow(A,s2); Mar D=B*C; D=T_Pow(D,s1); D=C*D; printf("%lld\n",(D.v1+D.v2)%MM); } return 0; }
解题思路:
可以暴力推出公式.费马小定理不适合于矩阵的次幂,a=c=1时,退化成等差数列,需特判,其余等比数列。这题这样做有问题。矩阵的次幂不能用费马小定理来降次,只是这题有点特殊。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) //#define ll __int64 #define ll long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define MM 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1100000 char s1[Maxn],s2[Maxn]; ll a,b,c,d,M; ll cal(char * s) { ll res=0; int i=0; while(s[i]) { res=(res*10+s[i]-'0')%M; i++; } return (res-1+M)%M; } struct Mar { ll s[3][3]; int row,col; void init(int a,int b) { row=a,col=b; memset(s,0,sizeof(s)); } }; struct Mar operator * (const struct Mar &a,const struct Mar &b) { Mar c; c.init(a.row,b.col); for(int k=1;k<=a.col;k++) { for(int i=1;i<=a.row;i++) { if(!a.s[i][k]) continue; for(int j=1;j<=b.col;j++) { if(!b.s[k][j]) continue; c.s[i][j]=(c.s[i][j]+a.s[i][k]*b.s[k][j])%MM; } } } return c; } Mar Pow(Mar aa,ll bb) { Mar c; c.init(aa.row,aa.col); c.s[1][1]=1,c.s[2][2]=1; while(bb) { if(bb&1) c=aa*c; bb>>=1; aa=aa*aa; } return c; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(~scanf("%s%s",s1,s2)) { scanf("%lld%lld%lld%lld",&a,&b,&c,&d); if(a==1&&c==1) M=MM; else M=MM-1; // M=MM-1; ll n=cal(s1),m=cal(s2); Mar A; A.init(2,2); A.s[1][1]=a,A.s[1][2]=b,A.s[2][2]=1; Mar B; B.init(2,2); B.s[1][1]=c,B.s[1][2]=d,B.s[2][2]=1; Mar C=Pow(A,m); Mar D=B*C; D=Pow(D,n); D=C*D; printf("%lld\n",(D.s[1][1]+D.s[1][2])%MM); } return 0; }
相关文章推荐
- 微信将是未来几年最具影响力的新媒体
- 改进的合并排序算法(小数组内使用插入排序算法)
- DLL搜索路径和DLL劫持
- phpcms v9调用自定义字段的方法
- windows2003的若干操作
- 雷军:互联网硬件的崛起便是小米加速度发展的风口
- 正则表达式grep sed awk总结
- 大型网站的推广方法
- jquery.validate.js插件使用简单说明
- perl学习笔记
- onclick与onClick
- Java中super关键字的用法及示例
- 安装一个tomcat可以运行多个tomcat实例
- JS中typeof与instanceof的区别
- thinkphp T方法
- C#中dynamic、ExpandoObject 的正确用法
- phpcms v9出现Can not connect to MySQL server错误的原因和解决方法
- 变量初始化
- XCode: An unknown error occurred.
- win8.1添加邮箱