您的位置:首页 > 大数据 > 人工智能

2017 Multi-University Training Contest - Team 2 :1006 Funny Function(找规律+逆元+快速幂取模)

2017-07-31 19:18 633 查看

Funny Function

[b]Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1192    Accepted Submission(s): 580
[/b]

[align=left]Problem Description[/align]
Function Fx,ysatisfies:



For given integers N and M,calculate Fm,1
modulo 1e9+7.

 

[align=left]Input[/align]
There is one integer T in the first line.

The next T lines,each line includes two integers N and M .

1<=T<=10000,1<=N,M<2^63.

 

[align=left]Output[/align]
For each given N and M,print the answer in a single line.

 

[align=left]Sample Input[/align]

2
2 2
3 3

 

[align=left]Sample Output[/align]

2
33

 

题目给出了三个公式。

第一行F[1][1] = F[1][2] = 1;

第一行的其他数F[i][j] = F[i][j-1] + 2*F[i][j-2]。 当j》=3的时候,

当i>=2的时候,F[i][j] 等于i-1行从j开始n个数的和。

给出n,m,求F【m,1】的值。

比赛时画了四张纸,还是没有找出规律,只是发现了n,m的奇、偶性对答案的影响时不同的。看官方题解和

其他人写的式子,我真的退不出来最后的公式,不过在网上发现了一篇文章,就是单纯的去讲他们当时比赛怎么

找规律找出来的,我还勉强可以理解理解。原文作者链接:https://www.dreamwings.cn/hdu6050/4839.html

首先找这种二维数组的规律,我们可以借助Excel表,有格子,比较好看。下面是我用Excel表制的数据

当时我们也写了挺多,就是在纸上写的太乱了,算了后面的数,前面的就丢了,不直观。还是Excel弄出来比较整齐。

或者可以编程计算将数据都写入文件。









然后开始找规律:

当n=2的时候,从第三行开始,发现6/2 = 3   18/6 = 3 54/18 = 3. 我们发现当n=2的时候,F[m][1]/F[m-1][1] = 3 (m>=3)

当n=4的时候,从第三行开始,发现150/10 = 15   2250/150=15.。。。我们发现当n=4的时候,F[m][1]/F[m-1][1] = 15 (m>=3)

这样来看比值3  和 n值2有什么关系,  比值15 和n值4有什么关系, 比较容易发现比值等于2^n-1.

那么规律都是这样的吗。

再来看n为奇数的情况。

然后我们来看当 nn
为奇数的情况,还照之前的做法我们把相邻的两项相除,可以发现这个值无限趋近于
2n−1,于是想到会不会相差某一个数字呢。

然后计算

Fm−1,1×(2n−1)−Fm,1,
F[m-1][1]*(2^n-1)-F[m][1] ,发现果真相差一个常数,接下来的工作便是寻找这个常数与什么有关了。

当 n=3..5..7..9n=3..5..7..9
时,该常数为: 2..10..42..1702..10..42..170
,有规律么?

答案当然是有啦~

2 = 2^1

10 = 2^1 + 2^3

42 = 2^1 + 2^3 + 2^5

170 = 2^1 + 2^3 + 2^5 + +2^7

................这个规律真的不太好找。

也就是公比为4,的等比数列的前k项和,公式Sk = a1*(1-q^k)/(1-q),其中首项a1 = 2,公比q = 4,项数k=n/2.将这些值带入上式就能得到,前k

项和。

我们设cha为我们所求得得差,假如F[2][1]时已知得,2^n-1也已知,然后我们如何通过这三者得到F[m][1]呢?

F[3][1] = F[2][1]*(2^n-1) - cha

F[4][1] = F[3][1]*(2^n-1) - cha = F[2][1]*(2^n-1)^2 - cha*(2^n-1) - cha

F[5][1] = F[4][1]*(2^n-1) - cha = F[2][1]*(2^n-1)^3 - cha*(2^n-1)^2  - cha*(2^n-1) - cha

....................

F[m][1] = F[m-1][1]*(2^n-1) - cha = F[2][1]*(2^n-1)^(m-2) - cha*(2^n-1)^(m-3)-.......- cha*(2^n-1)-cha

可以看出后面的  cha*(2^n-1)^(m-3) + cha*(2^n-1)^(m-4) + cha*(2^n-1)^(m-5) + ... + cha*(2^n-1)  + cha

把cha提出来后,又是一个等比数列求和,首相为1,公比为(2^n-1),项数为m-2。

则现在是只有F[2][1]不知道了,而F[2][1]又等于第一行前n项的和,那它怎么得到呢,每次给出一个n值,算出第一行

前n个数再求和吗?结果发现F[2][1]也又规律。下面的S[i]为第一行的前i项和,

同样也有规律的,先打表看看~

S[i]: 1 2 5 10 21 42 85 170 341 682 1365 2730 5461 10922 21845 43690 87381 174762 349525
F[i]: 1 1 3 5 11 21 43 85 171 341 683 1365 2731 5461 10923 21845 43691 87381 174763 349525

如果把s[i]整体往后推一位,

S[i]:      1   2    5    10   21    42    85    170   341   682    1365    2730    5461     10922     21845     43690     87381     174762    349525

F[i]: 1   1   3    5   11    21    43    85    171   341   683    1365    2731    5461     10923     21845     43691     87381     174763    349525

当n为奇数的时候,S
= F[2][1] = F[1][n+1]

当n为偶数的时候,S
= F[2][1] = F[1][n+1] - 1;

所以当给出一个n的时候,只要能算出F[1][n+1],就可以计算出F[2][1]的值。

看别人的博客推出F[1][n+1]也有一个公式F[1][n+1] = ( (-1)^i + 2^(i+1))/3,但是我都看不懂这个式子。

但是之前我用矩阵快速幂求过斐波那契数列,所以我就用矩阵快速幂推导第一行的第n+1项。

首先再第一行我们知道,对于n>=3                Fn = Fn-1 + 2*Fn-2.

则对于n>=3我们可以写出下列矩阵来推导



现在总结公式:



除法过程中取模要用到逆元,因为要取模的那个数时素数,所以可以用小费马定理去求逆元。

AC代码:

#include <iostream>
#include <stdio.h>

using namespace std;

const int mod = 1e9+7;
typedef long long LL;
/*F[1][i] = F[1][i-1] + 2*F[1][i-2],(i>=3)时成立,
又因为F[2][1]等于第一行前n项和相加,当n%2==0.sn = F[1][n+1]-1
当n%2==1,sn = F[1][n+1].所以可以通过矩阵快速幂求F[1][n+1].*/
struct Matrix
{
LL a[4][4];
};
///进行矩阵乘法的函数
Matrix Matrix_Mul(Matrix b,Matrix c)
{
Matrix tmp;
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
tmp.a[i][j] = 0;
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
for(int k = 1; k <= 2; k++)
tmp.a[i][j] = ((b.a[i][k]*c.a[k][j])%mod+tmp.a[i][j])%mod;
return tmp;
}
///矩阵快速幂计算F[1][n+1]
LL Matrix_Quick_Pow(LL k)
{
if(k==1 || k==2) return 1;
Matrix ans,res;
res.a[1][1] = 1; res.a[1][2] = 2;
res.a[2][1] = 1; res.a[2][2] = 0;
ans.a[1][1] = 1; ans.a[1][2] = 0;
ans.a[2][1] = 0; ans.a[2][2] = 1;
k = k-2;
while(k)
{
if(k&1)
ans = Matrix_Mul(ans,res);
res = Matrix_Mul(res,res);
k = k>>1;
}
return (ans.a[1][1]+ans.a[1][2])%mod;
}
///整数快速幂函数,求t的k次方
LL Integer_Quick_Pow(LL t,LL k)
{
LL ans,res;
ans = 1;
res = t;
while(k)
{
if(k&1)
ans = (ans*res)%mod;
res = (res*res)%mod;
k = k>>1;
}
return ans;
}
int main()
{
LL n,m,ans;
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
if(m == 1) cout<<"1"<<endl;
else
{
///矩阵快速幂计算F[1][n+1]。
LL Sn = Matrix_Quick_Pow(n+1);
if(n%2==0) Sn = (Sn-1+mod)%mod;   ///计算出F[2][1]
LL tmp1=Integer_Quick_Pow(2,n);   ///计算2^n
tmp1 = (tmp1-1+mod)%mod;          ///计算2^n-1
LL tmp2 = Integer_Quick_Pow(tmp1,m-2); ///计算(2^n-1)^(m-2)
if(n%2==0)
{
ans = (Sn*tmp2)%mod;
}
else
{
LL term = n/2;  ///项数
LL tmp3 = Integer_Quick_Pow(4,term);  ///4^term
tmp3 = (tmp3-1+mod)%mod;              ///4^term-1
LL x = Integer_Quick_Pow(3,mod-2);    ///求3的逆元
tmp3 = ((2*tmp3)%mod)*x%mod;
LL y = Integer_Quick_Pow((tmp1-1+mod)%mod,mod-2);
LL tmp4 = (tmp2-1+mod)%mod;
tmp4 = (tmp3*tmp4)%mod*y%mod;
ans = ((Sn*tmp2)%mod-tmp4+mod)%mod;
}
cout<<ans<<endl;
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐