UVA 10518 How Many Calls?
UVA_10518
??? 這個題目想到f(n)=f(n-1)+f(n-2)+1還是比較容易的,但如果能想到是f(n)=2*F(n)-1就不太容易了,在看了UVA的論壇之后我才知道原來可以表示成這個樣子,其中F(n)為斐波那契數,有了這個式子是第一步,后面的計算過程倒還不算麻煩。
? ? 后來在群里討論的時候,突然發現S(n)=F(n)+F(n+1)-1,S(n)為斐波那契的前n項和,這時又想到我之前推到的一個結論f(n)=S(n)-F(n-1),發現這個和f(n)=2*F(n)-1是可以轉化的,限于當時還不知道S(n)的表達式,所以錯過了推出結論的機會。
??? 先說說我推出f(n)=S(n)-F(n)的過程吧,我們在遞推計算遞歸次數的時候,每次的+1都另起一行來寫,這樣我們會得到下面的這個表。
? ? f(0) ? ? ?f(1) ? ? ?f(2) ? ? ?f(3) ? ? ?f(4) ? ? ?f(5) ? ? ?f(6)
???????????????????????????????????????????? ???????????????????1
????????????????????????????????????????????????????? 1???????? 1
??????????????????????????????????????????? 1???????? 1???????? 2
????????????????????????????????? 1???????? 1???????? 2???????? 3
??????????????????????? 1???????? 1? ???????2???????? 3???????? 5
??? 1???????? 1???????? 2???????? 3???????? 5???????? 8???????? 13
? ? 沒有數字的地方就可以看做是0,f(i)下面對應的整數和就是f(i)的值,相當于計算f(n)=f(n-1)+f(n-2)+1的時候,每行都進行f(n)=f(n-1)+f(n)的運算,最后再把1另起一行寫在上面。
? ? 這樣我們就能很明顯的看出來,每行都是一個斐波那契數列,不難得到f(n)=S(n)-F(n-1),這樣再把S(n)= F(n)+F(n+1)-1代入,就可以得到f(n)=2*F(n)-1。
? ? 不管用什么辦法,反正我們現在是得到f(n)的表達式了。下面回到題目,問題就轉化成了f(n)%b的值是多少,由于n很大所以我們在計算F(n)的時候不能直接遞推計算,于是可以把F(n)寫成矩陣的形式,然后用快速冪取模求得F(n)%b的值,進而就會有f(n)%b的值。
#include<stdio.h>#include<string.h>
#include<math.h>
long long int N, B;
long long int a[100][5], b[5];
void pow_mod(long long int n, int e)
{
if(n == 1)
{
a[e][0] = a[e][1] = a[e][2] = 1;
a[e][3] = 0;
return ;
}
pow_mod(n / 2, e + 1);
a[e][0] = (a[e + 1][0] * a[e + 1][0] + a[e + 1][1] * a[e + 1][2]) % B;
a[e][1] = (a[e + 1][0] * a[e + 1][1] + a[e + 1][1] * a[e + 1][3]) % B;
a[e][2] = (a[e + 1][2] * a[e + 1][0] + a[e + 1][3] * a[e + 1][2]) % B;
a[e][3] = (a[e + 1][2] * a[e + 1][1] + a[e + 1][3] * a[e + 1][3]) % B;
if(n % 2)
{
b[0] = (a[e][0] * a[0][0] + a[e][1] * a[0][2]) % B;
b[1] = (a[e][0] * a[0][1] + a[e][1] * a[0][3]) % B;
b[2] = (a[e][2] * a[0][0] + a[e][3] * a[0][2]) % B;
b[3] = (a[e][2] * a[0][1] + a[e][3] * a[0][3]) % B;
a[e][0] = b[0], a[e][1] = b[1], a[e][2] = b[2], a[e][3] = b[3];
}
}
void solve()
{
a[0][0] = a[0][1] = a[0][2] = 1;
a[0][3] = 0;
if(N == 0)
{
printf("1\n");
return ;
}
pow_mod(N, 1);
printf("%lld\n", (2 * a[1][0] + B - 1) % B);
}
int main()
{
int t = 0;
for(;;)
{
scanf("%lld%lld", &N, &B);
if(!N && !B)
break;
printf("Case %d: %lld %lld ", ++ t, N, B);
solve();
}
return 0;
}
轉載于:https://www.cnblogs.com/staginner/archive/2011/12/14/2288187.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的UVA 10518 How Many Calls?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uWSGI基础攻略
- 下一篇: 一些有意思的算法代码[转载]