Problem Description
Let us define a sequence as below
Your job is simple, for each task, you should output Fn module 109+7.
Input
The first line has only one integer T, indicates the number of tasks.
Then, for the next T lines, each line consists of 6 integers, A , B, C, D, P, n.
1≤T≤200≤A,B,C,D≤1091≤P,n≤109
Sample Input
2 3 3 2 1 3 5 3 2 2 2 1 4
Sample Output
36 24
题解:
题目给一个递推式,求Fn,很容易构造出递推矩阵
设3*3阶矩阵为Kn。
因为的值可能不同,所以需要分段求快速幂
例如p=100,n=3和n=4时的不同,所以F4=F3*K4
而n∈[51,100]时,的值都相等,所以=*,即分段后再求快速幂
将分段代码如下:
for (int i = 1;i <= p;i++) {
tmp1 = p / i;
if (tmp2 == tmp1)break;
kop[num++] = tmp1;
tmp2 = tmp1;
}
for (int i = tmp2 - 1;i > 0;i--)
kop[num++] = i;
大意是从大到小求使不同的n值,如果的值重复,则结束循环,后面的值依次递减即可。
下面贴出完整代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Matr = 4;
const ll mod = 1e9 + 7;
const int mmax = 1e5 + 7;
int kop[mmax];
struct mat
{
ll a[Matr][Matr], size;
mat(){
size = 0;
memset(a, 0, sizeof(a));
}
};
/*
void print(mat m)
{
int i, j;
printf("%d\n", m.size);
for (i = 1;i <= m.size;i++)
{
for (j = 1;j <= m.size;j++)printf("%d ", m.a[i][j]);
printf("\n");
}
}
*/
mat multi(mat m1, mat m2)
{
mat ans = mat(); ans.size = m1.size;
for (int i = 1;i <= m1.size;i++)
for (int j = 1;j <= m2.size;j++)
if (m1.a[i][j])
for (int k = 1;k <= m1.size;k++)
ans.a[i][k] = (ans.a[i][k] + m1.a[i][j] * m2.a[j][k]) % mod;
return ans;
}
mat quickmulti(mat m, mat op, int n)
{
mat ans = mat();
int i;
for (i = 1;i <= m.size;i++)
for (int j = 1;j <= 3;j++)
ans.a[i][j] = op.a[i][j];
ans.size = m.size;
while (n)
{
if (n & 1)ans = multi(m, ans);
m = multi(m, m);
n >>= 1;
}
return ans;
}
int main()
{
ll t, a, b, c, d, p, n, i;
cin >> t;
while (t--)
{
cin >> a >> b >> c >> d >> p >> n;
if (n <3)
{
cout << (n==1?a:b) << endl;
continue;
}
mat k, op;
k.a[1][1] = d;
k.a[1][2] = c;
k.a[1][3] = p;
k.a[3][3] = k.a[2][1] = 1;
k.a[2][2] = k.a[2][3] = k.a[3][1] = k.a[3][2] = 0;
k.size = 3;
for (int i = 1;i <= 3;i++)
op.a[i][i] = 1;
op.size = 3;
ll num = 0, tmp1, tmp2 = 0;
for (int i = 1;i <= p;i++) //计算分段的n值
{
tmp1 = p / i;
if (tmp2 == tmp1)break;
kop[num++] = tmp1;
tmp2 = tmp1;
}
for (int i = tmp2 - 1;i > 0;i--)
kop[num++] = i;
kop[num] = 0;
while (kop[num - 1] < 3) //n从3开始算起
num--;
kop[num] = 2;
//for (int i = 0;i < num;i++)
// cout << kop[i] << " ";
//cout << endl;
for (i = num - 1;i >= 0;i--)
{
if (n < kop[i])break;
k.a[1][3] = p / kop[i];
op = quickmulti(k, op, kop[i] - kop[i + 1]);
}
k.a[1][3] = p / n;
op = quickmulti(k, op, n - kop[i + 1]);
cout << ((op.a[1][1] * b + op.a[1][2] * a + op.a[1][3]) % mod) << endl;
}
//system("pause");
}