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


Funny Function

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1192    Accepted Submission(s): 580


Problem Description
Function Fx,y satisfies:

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

Input
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.
 

Output
For each given N and M,print the answer in a single line.
 

Sample Input
  
  
2 2 2 3 3
 

Sample Output
  
  
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为奇数的情况。

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

然后计算

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

n=3..5..7..9 n=3..5..7..9 时,该常数为: 2..10..42..170 2..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[n] = F[2][1] = F[1][n+1]

当n为偶数的时候,S[n] = 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;
}




























































































































  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值