题目链接

Problem Description

Function Fx,ysatisfies:

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

分析:

这道题最主要的是找到这一系列数之间的规律,数据范围那么大,肯定是有规律的,奈何比赛的时候找了好久还是没有把规律找对,当时是按照数之间的规律来找的,现在参考题解给出的规律,来看一下具体的解题方法:

下面具体的要用到矩阵快速幂的方法求解:

首先来推导矩阵A的形式:

同样的道理,对于矩阵B0,和B1:

这三个矩阵表示出来以后,就好解决了

矩阵减法就是两个矩阵相应位置上的元素相减,最后需要注意的是Fm,1还是要通过两个矩阵相乘求得的。

矩阵快速幂的算法思想还是很简单的,根整数快速幂思想一样,只是传进去的参数应该是矩阵。

#include <iostream>
#include <cstring>
#include<stdio.h>
using namespace std;
#define SIZE 2 struct matrix
{
long long e[SIZE][SIZE];
matrix()
{
memset(e, 0, sizeof(e));
}
} A, A_n; const long long mod = 1e9+7; //上限 matrix operator*(matrix &a, matrix &b)///两个矩阵相乘,行上的每个元素对应乘以列上的每个元素然后求和
{
matrix t;
for (int i = 0; i < SIZE; ++i)
{
for (int j = 0; j < SIZE; ++j)
{
for (int k = 0; k < SIZE; ++k)
{
t.e[i][j] += a.e[i][k]*b.e[k][j];
t.e[i][j] %= mod;
}
}
}
return t;
} matrix quickpower(matrix &a, long long b)///求矩阵的a的b次方,原理同整数幂一样
{
matrix ans;
for (int i = 0; i < SIZE; ++i)
{
ans.e[i][i] = 1;
}
while (b)
{
if (b & 1) ans = ans * a;
b >>= 1;
a = a * a;
} return ans;
} int main(int argc, char const *argv[])
{
int testn;
scanf("%d", &testn); while (testn--)
{
long long n, m;
scanf("%I64d %I64d", &n, &m);
///矩阵A
A.e[0][0] = 0;
A.e[1][0] = A.e[1][1] = 1;
A.e[0][1] = 2;
///求得矩阵An
A_n = quickpower(A, n); matrix b;
if(n & 1)
{
///矩阵B1
b.e[0][0] = -1;
b.e[0][1] = 2;
b.e[1][0] = 1;
b.e[1][1] = 0;
}
else
{
///矩阵B0
b.e[0][0] = b.e[1][1] = 1;
b.e[0][1] = b.e[1][0] = 0;
}
///矩阵An-B0(B1)
A_n.e[0][0] -= b.e[0][0];
A_n.e[0][1] -= b.e[0][1];
A_n.e[1][0] -= b.e[1][0];
A_n.e[1][1] -= b.e[1][1]; A_n = quickpower(A_n, m-1); long long ans = (A_n.e[0][0] + A_n.e[1][0]) % mod;
printf("%I64d\n", ans);
}
return 0;
}

这是题解里面给出的解题思路,其实自己根据观察第一列的元素也是可以总结出来规律的,这里就给个同学总结的完整版的讲解。

先将其一系列的数据打表:

C++n=2
1 1 3 5 11 21 43 85
2 4 8 16 32 64 128 256
6 12 24 48 96 192 384 768
18 36 72 144 288 576 1152 2304
n=3
1 1 3 5 11 21 43 85
5 9 19 37 75 149 299 597
33 65 131 261 523 1045 2091 4181
229 457 915 1829 3659 7317 14635 29269
n=4
1 1 3 5 11 21 43 85
10 20 40 80 160 320 640 1280
150 300 600 1200 2400 4800 9600 19200
2250 4500 9000 18000 36000 72000 144000 288000
n=5
1 1 3 5 11 21 43 85
21 41 83 165 331 661 1323 2645
641 1281 2563 5125 10251 20501 41003 82005
19861 39721 79443 158885 317771 635541 1271083 2542165
615681 1231361 2462723 4925445 9850891 19701781 39403563 78807125

要求的是F(m,1),则肯定与上面的结果有关系的,数据量过大,肯定是没有办法循环得到结果,由此看出,这道题必是规律题。

当n为奇数和偶数的时候,求F(m,1)的规律是不一样的。

偶数: 打表可以看出当n为偶数的时候,从F(2,1)开始,第一列的下一个是上一个的k倍,多打机组数据可看出,k为3,15,63,255……k的规律就是2^n-1。由此可得出,当n为偶数的时候,F(m,1) = F(2,1)×(2n-1)(m-2)。

奇数: 奇数求解的过程就相对来说比较复杂一点了。当n为奇数的时候,可以发现,F(m-1,1)×(2^n-1)与F(m,1)之间为一个常数k。我们就可以进一步的通过这样的关系求出F(m,1)的值

奇数求解过程:通过打表可以看出,当n等于3,5,7,9……的时候,k的值为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
……
//可以看出是等比为2^2的前k项和

结合上面可以得出:F(m-1,1)(2^n-1)-F(m,1) = Sk

F(m,1) = F(m-1,1)
(2^n-1)-Sk;

又可以根据这个公式推出

算到这里就仅仅剩下F(2,1)的求解了

先打表看看n:(1~i)第一行与F(2,1)的关系

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

F[i]表示当n为i时F(2,1)的值。

当i为奇数的时候F[i]=s[i+1];当i为偶数的时候F[i]=s[i+1]-1;

s[i+1]=((-1)i+2(i+1))/3;

接下来的求解过程就只需要注意边计算边取模就可以了。

注意:在对除数取余的时候为了防止精度的丢失,需要用到乘法的逆元,将除法变成乘法。这里使用的乘法逆元算法为费马小定理。

费马小定理

在p是素数的情况下,对任意整数x都有x^p≡x(mod)p。

可以在p为素数的情况下求出一个数的逆元,x∗x^(p−2)≡1(mod p),x^(p−2)即为逆元。

ll mult(ll a,ll n)  //求a^n%mod
{
ll s=1;
while(n)
{
if(n&1)s=s*a%mod;
a=a*a%mod;
n>>=1;
}
return s;
} //mult(a,n-2);

代码实现:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include<iostream>
using namespace std; typedef __int64 LL;
const int mod = 1e9+7;
LL n,m;
LL mult(LL a,LL n)
{
LL ans=1;
while(n)
{
if(n&1)ans=(ans*a)%mod;
a=(a*a)%mod;
n>>=1;
}
return ans;
} void solve()
{
if(m==1)
{
cout<<"1"<<endl;
return;
}
LL three=mult(3,mod-2); // 3 的逆元 费马小定理 求乘法逆元
LL one=((mult(2,n+1)+(n&1?-1:1)+mod)%mod*three)%mod; // F[1][n+1]
if(n%2==0)
one=(one-1+mod)%mod; // 计算 F[2][1]
LL ans=0;
LL mu=(mult(2,n)-1+mod)%mod; // 2^n-1
LL mun=mult(mu,m-2); // (2^n-1)^(m-2)
if(n%2==0) // 偶数时
ans=(one*mun)%mod;
else // 奇数时
{
LL cha=n/2;
cha=((2*(mult(4,cha)-1+mod)%mod)%mod)*three%mod;
LL add=((cha*(mun-1+mod)%mod)*mult((mu-1+mod)%mod,mod-2))%mod;
ans=((one*mun)%mod-add+mod)%mod;
}
cout<<ans<<endl;
} int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
cin>>n>>m;
solve();
}
return 0;
}

2017ACM暑期多校联合训练 - Team 2 1006 HDU 6050 Funny Function (找规律 矩阵快速幂)的更多相关文章

  1. 2017ACM暑期多校联合训练 - Team 8 1006 HDU 6138 Fleet of the Eternal Throne (字符串处理 AC自动机)

    题目链接 Problem Description The Eternal Fleet was built many centuries ago before the time of Valkorion ...

  2. 2017ACM暑期多校联合训练 - Team 5 1006 HDU 5205 Rikka with Graph (找规律)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  3. 2017ACM暑期多校联合训练 - Team 1 1006 HDU 6038 Function (排列组合)

    题目链接 Problem Description You are given a permutation a from 0 to n−1 and a permutation b from 0 to m ...

  4. 2017ACM暑期多校联合训练 - Team 4 1004 HDU 6070 Dirt Ratio (线段树)

    题目链接 Problem Description In ACM/ICPC contest, the ''Dirt Ratio'' of a team is calculated in the foll ...

  5. 2017ACM暑期多校联合训练 - Team 9 1005 HDU 6165 FFF at Valentine (dfs)

    题目链接 Problem Description At Valentine's eve, Shylock and Lucar were enjoying their time as any other ...

  6. 2017ACM暑期多校联合训练 - Team 9 1010 HDU 6170 Two strings (dp)

    题目链接 Problem Description Giving two strings and you should judge if they are matched. The first stri ...

  7. 2017ACM暑期多校联合训练 - Team 8 1002 HDU 6134 Battlestation Operational (数论 莫比乌斯反演)

    题目链接 Problem Description The Death Star, known officially as the DS-1 Orbital Battle Station, also k ...

  8. 2017ACM暑期多校联合训练 - Team 8 1011 HDU 6143 Killer Names (容斥+排列组合,dp+整数快速幂)

    题目链接 Problem Description Galen Marek, codenamed Starkiller, was a male Human apprentice of the Sith ...

  9. 2017ACM暑期多校联合训练 - Team 8 1008 HDU 6140 Hybrid Crystals (模拟)

    题目链接 Problem Description Kyber crystals, also called the living crystal or simply the kyber, and kno ...

随机推荐

  1. 【转载】mysql建表date类型不能设置默认值

    如题,mysql建表date类型的不能设置一个默认值,比如我这样: CREATE TABLE `new_table` ( `biryhday` datetime NULL DEFAULT '1996- ...

  2. 守护线程以及要使用时注意的一点(Daemon Thread)

    在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) Daemon的作用是为其他线程的运行提供便利服务,比如垃圾回收线程就是一个很称职的守护者.User和 ...

  3. daemon not running的解决办法

    有时候,当我们执行 adb devices 或者 adb start-server 的时候,会出现下面的情况: * daemon not running. starting it now on por ...

  4. HDU4466_Triangle

    今天比赛做的一个题目,不过今天终于感受到了复旦题目有多坑了. 题目的意思是给你一段长为n个单位长度的直线,你可以选择任意连续单位长度的线段组成三角形,可以组成任意你可以组成任意多个三角形,且要求其中所 ...

  5. 只要实现了annotation这个接口就是注解 同理:只要实现了某个接口就是该类型的实现类

    只要实现了annotation这个接口就是注解  同理:只要实现了某个接口就是该类型的实现类

  6. 移动端开发-viewport

    1.viewport viewport 即设备 屏幕上显示网页的区域.因为移动设备屏幕比较小,为了能让移动设备能够显示更多内容,默认设置的viewport 并不是屏幕真是像素点的宽度,一般为980px ...

  7. Luogu4897 【模板】最小割树

    没事干写一发模板. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib& ...

  8. C++解析(9):关于const和引用的疑问

    0.目录 1.关于const的疑问 2.关于引用的疑问 2.1 引用与指针 2.2 从C++语言与C++编译器角度看引用 2.3 从工程项目开发看引用 3.小结 1.关于const的疑问 const什 ...

  9. P1107 [BJWC2008]雷涛的小猫

    题目描述 雷涛同学非常的有爱心,在他的宿舍里,养着一只因为受伤被救助的小猫(当然,这样的行为是违反学生宿舍管理条例的).在他的照顾下,小猫很快恢复了健康,并且愈发的活泼可爱了. 可是有一天,雷涛下课回 ...

  10. [JLOI2011]飞行路线 最短路

    题面 题面 题解 这题不是很难,因为删代价的次数不多,因此我们只需要将最短路中的状态加一维表示已经删了几次,再转移即可 #include<bits/stdc++.h> using name ...