Transcript

ACM程序设计

东北林业大学 陈宇[email protected]

今天你 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; } 

矩阵的快速幂运算

#include <cstdio> const int MAX = 3; typedef  struct{         int  m[MAX][MAX]; }  Matrix; Matrix P={5,-7,4, 1,0,0, 0,1,0,};

Matrix P={1,0,0, 0,1,0, 0,0,1,};

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; }

矩阵连乘的函数

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; }

fibonacci 与构造矩阵

Fibonacci 的基本递推公式:

求解递推方程就可以解出如下的通项公式:

封闭形式的通项公式:

nn

nf 2

51

2

51

5

1

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 本题也可以用矩阵乘法。

本题用循环节的做法 // 自己本地打出 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; }

用矩阵乘法(直接用模版即可)

)2()1(

)1(

)(

)1(

)1(

)2(

nfnf

nf

nf

nf

nf

nf

11

10

)2(

)1(

)1(

)0(

11

101

f

f

f

f

)1(

)(

)1(

)0(

11

10

nf

nf

f

fn

把左边的矩阵自己根据右边的值,求出!

最后的公式:

)1(

)(

11

7

11

10

nf

nfn

11

10A

用矩阵连乘模版,对 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++

详细代码: #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};

矩阵乘法

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; }

矩阵连乘(二分)的调用 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; }

主函数 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; }

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.

算到 2005 位

Note: No generated Fibonacci number in excess of

2005 digits will be in the test data, ie. F(20) = 66526 has 5 digits.

#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];

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++;

}

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; }

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 说的是否正确。

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, 取对数,就可以了。

#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--;

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; }

hdu 3117

Hdu-3117: For each test case, a line will contain an integer i bet

ween 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).

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

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

解题报告: 下面举例来说明计算前 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) 的值用上面方法

#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};

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; }

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; }

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;

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; }

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)

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.

sample_input 1 1 3 5 10 1000 0 0

sample_output 1 16 496035733

公式推导

)1(

)2()1(

)2()1()1(

)1(

)(

)(

)2(

)1(

)1(

010

110

111

nf

nfnf

nfnfns

nf

nf

ns

nf

nf

ns

)1(

)(

)(

)0(

)1(

)1(

010

110

1111

nf

nf

ns

f

f

sn

)1()( asbs 为所求!

代码:注意取余相减会出现负数! #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};

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; }

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; }

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;

}

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; }

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.

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

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.

Sample Input 2 1 1 3 2 3

Sample Output 6 196

)2()1()1(

)1(

)2()2()1(2)1(

)1()2(

)1()(

)1(

)(

)1(

)2()1(

)2(

)1(

)2(

2

2

2222

2

2

2

2

2

nfnyfnxf

nf

nfynfnxyfnfx

nfns

nfnf

nf

nf

ns

nfnf

nf

nf

ns

yx

xyyxA

00

0010

20

001122

注意: 注意每一步都要取模,别怕麻烦; 对于 x 和 y 要是取负数的话(本题没有),

则要 (data%mod+mod)%mod; 正的就直接 data%mod 就行; typedef struct{ int m[MAX][MAX];     } Matrix;    该结构体的定义要注意,若将 int 类型

换成 long long ,则运行时间会翻倍,可能会TLE, 注意哦