二分法
数学的魅力:
幂运算满足结合律
n为偶数: a^n=a^(n/2)*a^(n/2);
n为奇数: a^n=a^(n/2)*a^(n/2)*a;
保存a^(n/2),很容易求出a^n;
大数取模
(a*b)%m=(a%m*b%m )%m;
求(2^100000000000000)%10000;
提示:二分法,速度惊人的快速幂!!!
此题一般的数代码如下:
#include<iostream> using namespace std; #include<math.h> __int64 fun(__int64 m,__int64 n,__int64 k) { __int64 s; if(n==1)return m%k; if(n%2==0) { n/=2; s=fun(m,n,k)%k; return (s*s)%k; } else { n/=2; s=fun(m,n,k)%k; return (s*s*(m%k))%k; } } int main() { freopen("d:\\1.txt","r",stdin); __int64 m,n,k; __int64 s1,s2; scanf("%I64d%I64d%I64d",&m,&n,&k); printf("%I64d\n",s1=fun(m,n,k)); printf("%I64d\n",s2=(int)(pow(m,n))%k);//检测是否正确 只能检测2^31-1,即n<32 if(s1==s2)printf("程序正确\n"); else printf("不正确,程序错误- _ -\n"); return 0; }
(a+b)%m=(a%m+b%m)%m;
例如:若Sn为斐波那契数列前10000项的和,
求Sn%10000;
f(1)=1,f(2)=1,f(3)=2......
方法1:一般递归方法的代码,当n很大时用时显然较长:
#include<iostream> #include<time.h> using namespace std; int Fi(int n,int k) { if(n==1||n==2)return 1%k; else return (Fi(n-1,k)%k+Fi(n-2,k)%k)%k; } int main() { int n,k,i; double start=time(NULL),end; //freopen("d:\\1.txt","r",stdin); cin>>n>>k; int s=0; for(i=1;i<=n;i++) s=(s+Fi(i,k))%k; printf("%d\n",s); end=time(NULL); printf("时间=%.2lf\n",end-start); return 0; }
方法2:不用递推,先将每一个Fibonacci数的对k求余的值保存在一个数组中,这样运行时间很短,不过适用于n不是太大的情况,代码如下:
#include<iostream> using namespace std; #include<time.h> int a[10010]={0}; void fun(int k) { a[1]=1%k; a[2]=1%k; for(int i=3;i<=10000;i++)//先将每一个数的值保存在数组中 a[i]=(a[i-1]%k+a[i-2]%k)%k; } int main() { //freopen("d:\\1.txt","r",stdin); double start=time(NULL),end; int n,k,i; cin>>n>>k; fun(k); int s=0; for(i=1;i<=n;i++) s=(s+a[i])%k; printf("%d\n",s); end=time(NULL); printf("%.2lf\n",end-start); return 0; }
方法3:
下面用矩阵法,然后对矩阵连乘用二分法:
若要求f(1)-f(10000)的和对m取模,用方法2较合适,若只求f(n)对m取模并且n非常大,比如n=1000000000,则用矩阵二分法,效果比方法2更为显著,代码如下:
#include<iostream> using namespace std; #include<time.h> int a=1,b,c=1,d; //要声明为全局变量,先将a c赋值,以解决当n<3的情况 void fun(int n,int k) { int t1,t2,t3,t4; if(n==1){a=1;b=1;c=1;d=0;return;}//注意必须加return返回 因为这是递归,必须有返回 if(n%2==0) { n/=2; fun(n,k); t1=a;//必须替换原来的数,因为下面要用到 t2=b; t3=c; t4=d; a=(t1*t1+t2*t3)%k; b=(t1*t2+t2*t4)%k; c=(t3*t1+t4*t3)%k; d=(t3*t2+t4*t4)%k; } else { n/=2; fun(n,k); t1=a; t2=b; t3=c; t4=d; a=(t1*t1+t2*t3)%k; b=(t1*t2+t2*t4)%k; c=(t3*t1+t4*t3)%k; d=(t3*t2+t4*t4)%k; int t5=a,t6=c; a=(t5+b)%k; b=t5%k; c=(t6+d)%k; d=t6%k; } } int main() { freopen("d:\\1.txt","r",stdin); double start=time(NULL),end; int n,k; cin>>n>>k; if(n<3) printf("%d\n",(a+c)%k); else { fun(n-2,k); printf("%d\n",(a+c)%k); } end=time(NULL); printf("%.2lf\n",end-start); return 0; }