1 / 51

ACM 程序设计

ACM 程序设计. 东北林业大学 陈宇 Lg_chenyu@yahoo.com.cn. 今天你 AC 了吗?. 第8讲 二分和构造矩阵. 快速幂 运算. int quickpow(int m,int n,int k) {    int b = 1;     while (n > 0)     {          if (n & 1)              b = (b*m)%k;           n = n >> 1 ;           m = (m*m)%k;     }    return b; } . 矩阵的快速幂运算.

shania
Télécharger la présentation

ACM 程序设计

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ACM程序设计 东北林业大学 陈宇 Lg_chenyu@yahoo.com.cn

  2. 今天你AC 了吗?

  3. 第8讲 二分和构造矩阵

  4. 快速幂运算 • int quickpow(int m,int n,int k) • {    int b = 1;     • while (n > 0)    •  {          if (n & 1)  •             b = (b*m)%k;   •         n = n >> 1 ;    •        m = (m*m)%k;    •  }    return b; • } 

  5. 矩阵的快速幂运算 • #include <cstdio> • const int MAX = 3; • typedef  struct{  •        int  m[MAX][MAX]; • }  Matrix; • Matrix P={5,-7,4, • 1,0,0, • 0,1,0,};

  6. Matrix P={1,0,0, • 0,1,0, • 0,0,1,};

  7. Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法{       int i,j,k;       Matrix c;   •      for (i = 0 ; i < MAX; i++)  •           for (j = 0; j < MAX;j++)   •            {                 c.m[i][j] = 0;  •           for (k = 0; k < MAX; k++)  •  c.m[i][j] += (a.m[i][k] * b.m[k][j])%9997; •            c.m[i][j] %= 9997;             • }       •  return c; • }

  8. 矩阵连乘的函数 • Matrix quickpow(long long n) • {       Matrix m = P, b = I;        • while (n >= 1)      •   {             if (n & 1)        •          b = matrixmul(b,m);   •            n = n >> 1;  •             m = matrixmul(m,m);       •  }     •    return b; • }

  9. fibonacci与构造矩阵 • Fibonacci的基本递推公式: • 求解递推方程就可以解出如下的通项公式: • 封闭形式的通项公式:

  10. hdu 1021 • hdu_1021: • Problem Description • There are another kind of Fibonacci numbers: F(0) = 7, F(1) = 11, F(n) = F(n-1) + F(n-2) (n>=2). • Input • Input consists of a sequence of lines, each containing an integer n. (n < 1,000,000). •  Output • Print the word "yes" if 3 divide evenly into F(n).Print the word "no" if not. • 解题报告: 观察法 找出循环节=8 然后%8=2或 %8=6 就YES • 本题也可以用矩阵乘法。

  11. 本题用循环节的做法 • //自己本地打出f(1)-f(50)对3取余的值,然后用眼睛观察,找出循环节。 • #include <iostream> • using namespace std; • int main() • { • int n; • while(cin>>n) • { • int k=n%8; • if (k==2||k==6) cout<<"yes"<<endl; • else cout<<"no"<<endl; • } • //cout << "Hello world!" << endl; • return 0; • }

  12. 用矩阵乘法(直接用模版即可) 把左边的矩阵自己根据右边的值,求出!

  13. 最后的公式: 用矩阵连乘模版,对3取余!设A^n=B,f(n)=B(1,1)*7+B(1,2)*11,B(1,1)表示第一行第1列,提交0MS搞定! 6939144 2012-10-18 09:23:37 Accepted 1021 0MS 300K 1164 B G++

  14. 详细代码: • #include <iostream> • #include <stdio.h> • #include <cstring> • #define Mod 3 • using namespace std; • const int MAX = 2; • typedef struct{ • int m[MAX][MAX]; • } Matrix; • Matrix P={0,1, • 1,1}; • Matrix I={1,0, • 0,1};

  15. 矩阵乘法 • Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法 • { • int i,j,k; • Matrix c; • for (i = 0 ; i < MAX; i++) • for (j = 0; j < MAX;j++) • { • c.m[i][j] = 0; • for (k = 0; k < MAX; k++) • c.m[i][j] += (a.m[i][k]* b.m[k][j])%Mod; • c.m[i][j] %= Mod; • } • return c; • }

  16. 矩阵连乘(二分)的调用 • Matrix quickpow(long long n) • { • Matrix m = P, b = I; • while (n >= 1) • { • if (n & 1) • b = matrixmul(b,m); • n = n >> 1; • m = matrixmul(m,m); • } • return b; • }

  17. 主函数 • int main() • { • Matrix ans; • int n,sum; • while(cin>>n) • { • if (n==0) {cout<<"no"<<endl; continue;} • ans=quickpow(n); //这句就计算矩阵的n次方对3取余了 • sum=ans.m[0][0]*7+ans.m[0][1]*11; • sum=sum%3; • if (sum==0) cout<<"yes"<<endl; • else • cout<<"no"<<endl; • } • return 0; • }

  18. Hdu_1250: • Hdu_1250: • Problem Description • A Fibonacci sequence is calculated by adding the previous two members the sequence, with the first two members being both 1.F(1) = 1, F(2) = 1, F(3) = 1,F(4) = 1, F(n>4) = F(n - 1) + F(n-2) + F(n-3) + F(n-4)Your task is to take a number as input, and print that Fibonacci number.

  19. 算到2005位 • Note: • No generated Fibonacci number in excess of 2005 digits will be in the test data, ie. F(20) = 66526 has 5 digits.

  20. #include <iostream> • #define m 2008 • using namespace std; • char data[8760][m+2]; • int main() • { • int i=5,p=m,n,num; • data[1][m]=1; • data[2][m]=1; • data[3][m]=1; • data[4][m]=1; • while(data[i-1][1]<=1) • { • for(int j=m;j>=p;j--) • data[i][j]=data[i-1][j]+data[i-2][j]+data[i-3][j]+data[i-4][j];

  21. for(int j=m;j>=p;j--) • { • int c=data[i][j]/10; • if (c>0) • { • data[i][j]=data[i][j]%10; • data[i][j-1]+=c; • } • } • if (data[i][p-1]>0) p--; • i++; • }

  22. while(cin>>n) • { • for (int k=0;k<=m;k++) • if (data[n][k]!=0) {num=k;break;} • for(int k=num;k<=m;k++) cout<<(int)data[n][k]; • cout<<endl; • } • // cout << "Hello world!" << endl; • return 0; • }

  23. Hdu-1568: • 7007年到来了。经过2006年一年的修炼,数学神童zouyu终于把0到100000000的Fibonacci数列(f[0]=0,f[1]=1;f[i] = f[i-1]+f[i-2](i>=2))的值全部给背了下来。接下来,CodeStar决定要考考他,于是每问他一个数字,他就要把答案说出来,不过有的数字太长了。所以规定超过4位的只要说出前4位就可以了,可是CodeStar自己又记不住。于是他决定编写一个程序来测验zouyu说的是否正确。

  24. Input • 输入若干数字n(0 <= n <= 100000000),每个数字一行。读到文件尾。 • Output • 输出f[n]的前4个数字(若不足4个数字,就全部输出)。 • 解题报告: • 因为是前4位,所以可以用封闭公式: 1/sqrt(5).((1+sqrt(5))/2.0)^n ,再设f(n)=d.xxxxx*10^x,取对数,就可以了。

  25. #include <iostream> • #include <math.h> • using namespace std; • int data[50]; • int main() • { • int k,n; • double val,bit; • data[0]=0;data[1]=1; • for(int i=2;i<=50;i++) • {data[i]=data[i-1]+data[i-2]; • if (data[i]>9999) {k=i;break;} • } • k--;

  26. while(cin>>n) • { • if (n<=k) cout<<data[n]<<endl; • else • { • val=log10(1.0/sqrt(5.0))+n*log10((1.0+sqrt(5.0))/2.0); • bit=val-(int)val; • //cout<<bit<<endl; • int d=(int)(pow(10,bit+3)); • cout<<d<<endl; • } • } • //cout << "Hello world!" << endl; • return 0; • }

  27. hdu 3117 • Hdu-3117: • For each test case, a line will contain an integer i between 0 and 10^8 inclusively, for which you must compute the ith Fibonacci number fi. Fibonacci numbers get large pretty quickly, so whenever the answer has more than 8 digits, output only the first and last 4 digits of the answer, separating the two parts with an ellipsis (“...”). There is no special way to denote the end of the of the input, simply stop when the standard input terminates (after the EOF).

  28. Sample Input • 0 • 1 • 2 • 3 • 4 • 5 • 35 • 36 • 37 • 38 • 39 • 40 • 64 • 65

  29. Sample Output • 0 • 1 • 1 • 2 • 3 • 5 • 9227465 • 14930352 • 24157817 • 39088169 • 63245986 • 1023...4155 • 1061...7723 • 1716...7565

  30. 解题报告: • 下面举例来说明计算前4位 • 123456.32=1234.56*10^2 • s=d.xxx*10^(len-4) • log10(s)=log10(d.xxxxx)+log10(10^(len-4))=log10(d.xxxx)+len-4; • log10(s)+4-len=log10(d.xxxx) • d.xxxx=10^(log10(s)+4-len) • s=(1/sqrt(5))*[(1+sqrt(5))/2.0]^i; • len=(int)log10(s)+1; • d.xxxx=10^(log10(s)+4-((int)log10(s)+1))=10^(log10(s)-(int)log10(s)+3); • ----------------------------------------------------------------------------- • 计算后4位 矩阵乘法幂取模,注意后4位时 ,例如 0123 输出要占4位,而不是123 • 先把前8位的fibonacci的值打表打出来;8位以后的f(i)的值用上面方法

  31. #include <iostream> • #include <stdio.h> • #include <math.h> • #define Mod 10000 • using namespace std; • long long f[100]; • const int MAX = 2; • typedef struct{ • long long m[MAX][MAX]; • } Matrix; • Matrix P = {0,1, • 1,1}; • Matrix I = {1,0, • 0,1};

  32. Matrix matrixmul(Matrix a,Matrix b) //矩阵乘法 • { • int i,j,k; • Matrix c; • for (i = 0 ; i < MAX; i++) • for (j = 0; j < MAX;j++) • { • c.m[i][j] = 0; • for (k = 0; k < MAX; k++) • c.m[i][j] += (a.m[i][k] * b.m[k][j])%Mod; • c.m[i][j] %= Mod; • } • return c; • }

  33. Matrix quickpow(long long n) • { • Matrix m = P, b = I; • while (n >= 1) • { • if (n & 1) • b = matrixmul(b,m); • n = n >> 1; • m = matrixmul(m,m); • } • return b; • }

  34. int main() • { • //int aaaa=123; • //printf("%04d\n",aaaa); • double log_s=0.0; • Matrix tmp; • int n,bit=0; • f[0]=0; • f[1]=1; • for(int i=2;i<=50;i++) • { • f[i]=f[i-1]+f[i-2]; • if (f[i]>=100000000) • { bit=i-1;break; } • } • //cout<<f[12]<<endl;

  35. while(cin>>n) • { • if (n<=bit) cout<<f[n]<<endl; • if (n>bit) • { • tmp=quickpow(n); • int ans_e=tmp.m[0][1]; • log_s=log10(1.0/sqrt(5)) +(double)n*log10((1.0+sqrt(5))/2.0); • int ans_s=(int)(pow(10,log_s-(int)log_s+3)); • cout<<ans_s<<"..."; • printf("%04d\n",ans_e); • } • } • //cout<<quickpow(2,3,5)<<endl; • //cout << "Hello world!" << endl; • return 0; • }

  36. nefu 463 fibs之和 • description • As we know , the Fibonacci numbers are defined as follows: • F(0)=1,f(1)=1;f(n)=f(n-1)+f(n-2) n>=2; • Given two numbers a and b , calculate S(n)=f(a)+f(a+1)+….+f(b)

  37. input • The input contains several test cases. Each test case consists of two non-negative integer numbers a and b (0 ≤ a ≤ b ≤1,000,000,000). Input is terminated by a = b = 0. • output • For each test case, output S(n) mod 1,000,000,000, since S(n) may be quite large.

  38. sample_input • 1 1 • 3 5 • 10 1000 • 0 0 • sample_output • 1 • 16 • 496035733

  39. 公式推导 为所求!

  40. 代码:注意取余相减会出现负数! • #include <iostream> • #define val 1000000000; • using namespace std; • const int MAX = 3; • typedef struct{ • long long m[MAX][MAX]; • } Matrix; • Matrix P = {1,1,1, • 0,1,1, • 0,1,0}; • Matrix I = {1,0,0, • 0,1,0, • 0,0,1};

  41. Matrix matrixmul(Matrix a,Matrix b) //������������ • { • int i,j,k; • Matrix c; • for (i = 0 ; i < MAX; i++) • for (j = 0; j < MAX;j++) • { • c.m[i][j] = 0; • for (k = 0; k < MAX; k++) • c.m[i][j] =(c.m[i][j]+(a.m[i][k]*b.m[k][j]))%val; • c.m[i][j] %= val; • } • return c; • }

  42. Matrix quickpow(long long n) • { • Matrix m = P, b = I; • while (n >= 1) • { • if (n & 1) • b = matrixmul(b,m); • n = n >> 1; • m = matrixmul(m,m); • } • return b; • }

  43. int main() • { • int a,b; • Matrix ans_a,ans_b; • int data[3]; • data[0]=1; • data[1]=2; • data[2]=4; • long long ans1,ans2; • while(cin>>a>>b) • { • if (a==0&&b==0) break; • if (a>2) • { • ans_a=quickpow(a-2); • ans1=(ans_a.m[0][0]*2+ans_a.m[0][1]+ans_a.m[0][2])%val; • } • if (b>1) • { • ans_b=quickpow(b-1); • ans2=(ans_b.m[0][0]*2+ans_b.m[0][1]+ans_b.m[0][2])%val; • }

  44. if (a==0&&b==1) {cout<<2<<endl;continue;} • if (a==0&&b>1) {cout<<ans2<<endl;continue;} • if (a>0&&a<=2) ans1=data[a-1]; • if (b>0&&b<=2) ans2=data[b]; • //cout<<ans1<<" "<<ans2<<endl; • long long ans3=ans2-ans1; //可能为负数 • ans3%=val; • if (ans3<0) ans3=ans3+val; //相减小于0时,加上模 • cout<<ans3<<endl; • } • return 0; • }

  45. Another kind of Fibonaccihdu 3306 • As we all known , the Fibonacci series : F(0) = 1, F(1) = 1, F(N) = F(N - 1) + F(N - 2) (N >= 2).Now we define another kind of Fibonacci : A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) (N >= 2). • And we want to Calculate S(N) , S(N) = A(0)^2 +A(1)^2+……+A(n)^2.

  46. Input • There are several test cases. • Each test case will contain three integers , N, X , Y . • N : 2<= N <= 2^31 – 1 • X : 2<= X <= 2^31– 1 • Y : 2<= Y <= 2^31 – 1

  47. Output • For each test case , output the answer of S(n).If the answer is too big , divide it by 10007 and give me the reminder.

  48. Sample Input • 2 1 1 • 3 2 3 • Sample Output • 6 • 196

More Related