补题记录-求通项公式+矩阵快速幂

链接:https://codeforces.com/gym/247236/problem/I

题面

Nate’s math teacher thinks he watches too much anime and not enough time studying for their algebra test. Nate insists that he’s already prepared for the test, but in order to prove it, he has to solve the following problem that his teacher gave him.
Given a, n, and that x2−ax+1=0, find b such that x2n−bxn+1=0.
Input
The first line of input contains a single integer T, the number of test cases. The next T lines of input each contain two space-separated integers a and n, respectively, the values in the equation.
Constraints
1≤T≤105
|a|,|n|≤1018
Output
For each of the T test cases, output in its own line a single integer, b, that satisfies the equation. Since the answer can get quite large, output only the positive remainder when b is divided by 109+7, a prime number. It can be proven that b is always an integer.
Example
input
3
2 1231
2 10000000
5 0

output
2
2
2

题意

已知x2+ax=1,x2*n+bxn=1,给你a和n,求b%(1e9+7)的值。b是正整数。

思路

首先很容易得出a=x+1/x,b=xn+1/xn
然后设f(n)=xn+1/xn。经过计算(找规律?),可以得出递推式f(n)=a * f(n-1)-f(n-2).
那么想到斐波那契舒数列的求解方法了。
直接上干货:
如果f(n)=af(n-1)+bf(n-2)+c,那么可以如下利用矩阵来求解。

如果c==0的话,那么第三行和第三列可以省略。
这里在加上一种常用的情况如果f(n)=cn-f(n-1) ;(c是常数)
那么就有

所以,假设上述矩阵可以表示为T(n)*F(n-1)=F(n),则F(n)=T(n)n-2F(2)。
这一注意MOD一个数的时候,如果是负数模MOD,那么需要(num%MOD+MOD)%MOD不然结果会出错。因为负数取模依然是个负数。(因为这个wa了无数发)

代码

//#include<bits/stdc++.h>//https://codeforces.com/gym/247236/problem/Iwwdsadwsadwa
#include<algorithm>
#include<complex>
#include<iostream>
#include<iomanip>
#include<ostream>
#include<cstring>
#include<string.h>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<cstdlib>
#include<time.h>
#include<ctime>
#include<bitset>
#define pb push_back
#define _fileout freopen("out.txt","w",stdout)
#define _filein freopen("in.txt","r",stdin)
#define ok(i) printf("ok%d\n",i)
using namespace std;
typedef double db;
typedef long long ll;
const double PI = acos(-1.0);
const ll MOD=1e9+7;
const int MAXN=2e3+10;
const int INF=0x3f3f3f3f;
const ll ll_INF=9223372036854775807;
const double eps=1e-8;
ll qm(ll a,ll b){ll ret = 1;while(b){if (b&1)ret=ret*a%MOD;a=a*a%MOD;b>>=1;}return ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return (a*b)/gcd(a,b);}
ll t,n;
int b[2][2];
int ans[2][2];
int mid[2][2];
inline ll add(const ll &a ,const ll &b)
{
    return (a+b)>=MOD?(a+b)-MOD:(a+b<0?(a+b)+MOD:a+b);
}
inline ll mul(const ll &a,const ll &b)
{
    return 1ll*a*b%MOD;
}
void pow()
{
    while(n)
    {
        
        if(n&1)
        {
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    mid[i][j]=0;
                    for(int k=0;k<2;k++){
                        mid[i][j]=add(mid[i][j],mul(ans[i][k],b[k][j]));
                    }
                }
            }
            memcpy(ans,mid,sizeof ans);
        }
        
        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                mid[i][j]=0;
                for(int k=0;k<2;k++){
                    mid[i][j]=add(mid[i][j],mul(b[i][k],b[k][j]));
                }
            }
        }
        memcpy(b,mid,sizeof b);
        n>>=1;
    }
}
int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        scanf("%I64d%I64d",&t,&n);
        n=abs(n);
        int a=(t%MOD+MOD)%MOD;
        if(n==0)
        {
            printf("2\n");
            continue;
        }
        else if(n==1)
        {
            printf("%d\n",a);continue;
        }
        n-=2;
        ans[0][0]=ans[1][1]=1;
        ans[0][1]=ans[1][0]=0;
        b[0][0]=0;
        b[0][1]=1;
        b[1][0]=MOD-1;
        b[1][1]=a;
        pow();
        // show(ans);
        ll x=0;
        x=add(mul(ans[1][0],a),mul(ans[1][1],add(mul(a,a),-2)));
        printf("%I64d\n",x);
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值