传送门:HDU6050
题意:就是根据给出的公式求Fm,1.
官方题解:
进而推导出
通过矩阵快速幂求解
个人感觉除了不知道第一个式子是怎么来的,后边的根据上面步骤一步步推导还是能推出来的,然而让我自己想的话是不可能做出来的,但是比赛的时候有很多人出这个题,就很慌,赛后发现大佬们很多都是直接推出了个线性的通项式子。。太TM强了吧。。式子放在下面了,虽然不知道怎么来的。。
F(m,1)=(2*k1^(m-1)+(1+(-1)^(m+1))/2)/3 其中k1=(2^n-1);
还有就是这题我用vector套vector模拟二维数组,常数大的吓人,人家数组写顶多100+ms,我直接998ms。。没T也算是上帝保佑了。。以后还是正八经写吧,不搞这些骚东西了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
#define pi acos(-1)
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define rep(i,x,n) for(int i=x;i<n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
using namespace std;
typedef pair<int,int>P;
const int mod = 1e9 + 7;
const int MAXN=100010;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
typedef vector<ll> vec;
typedef vector<vec> mat;
mat mul(mat &A, mat &B)
{
int n = A.size(), m = B[0].size(), p = B.size();
mat C(n, vec(m, 0));
for(int k = 0; k < p; k++)
for(int i = 0; i < n; i++)
{
if(A[i][k] == 0) continue;
for(int j = 0; j < m; j++)
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % mod;
}
return C;
}
mat qpow(mat &A, ll n)//求A的n次方
{
mat B(A.size(), vec(A.size(),0)), C = A;
for(int i = 0; i < B.size(); i++)
B[i][i] = 1;
while(n)
{
if(n & 1) B = mul(B, C);
C = mul(C, C);
n >>= 1;
}
return B;
}
int main()
{
mat B0(2, vec(2, 0)), B1(2, vec(2, 0));
B0[0][0] = B0[1][1] = 1;
B1[0][1] = 1;
B1[1][0] = 2;
B1[1][1] = -1;
int T;
ll n, m;
scanf("%d", &T);
while(T--)
{
scanf("%lld %lld", &n, &m);
mat A(2, vec(2, 0)), F(2, vec(2, 0));
A[0][0] = A[0][1] = 1;
A[1][0] = 2;
F[0][0] = F[0][1] = 1;
if(n & 1)
{
A = qpow(A, n);
A[0][1] -= B1[0][1];
A[1][0] -= B1[1][0];
A[1][1] -= B1[1][1];
A = qpow(A, m - 1);
F = mul(F, A);
printf("%lld\n", F[0][1]);
}
else
{
A = qpow(A, n);
A[0][0] -= B0[0][0];
A[1][1] -= B0[1][1];
A = qpow(A, m - 1);
F = mul(F, A);
printf("%lld\n", F[0][1]);
}
}
return 0;
}