HDU4565

题意:

给出a,b,n,m,求。其中

思路:

首先根据构造共轭因式的思想,构造下式:

注意一个条件,,则,则,则有,

因为

①和②相加得

所以

对于的递推公式,可以有多种方法推导得到,这里说其中两种。

法一:二阶线性递推式

定理:对于由递推公式给出的数列,方程,叫做数列的特征方程。

这里是特征方程的两个根,可以由韦达定理推出特征方程为,所以有递推公式

法二:递推

所以

这样就可以构造矩阵了,

再用矩阵快速幂做就可以了。

这里要注意,可能是负的,所以在矩阵乘法中取模的时候要加上模数再取模。

代码:

typedef long long ll;
struct mat
{
    long long a[2][2];
}m,r;
ll p;
mat mult(mat x,mat y)
{
    mat res={0};
    int i,j,k;
    for(i=0;i<2;i++)
        for(j=0;j<2;j++)
            for(k=0;k<2;k++)
                res.a[i][j]=(res.a[i][j]+(x.a[i][k]*y.a[k][j])%p+p)%p;
    return res;
}
mat PowerMod(mat x,long long n)
{
    mat ans={0};
    int i;
    for(i=0;i<2;i++)
        ans.a[i][i]=1;
    while(n>0)
    {
        if(n%2==1)
            ans=mult(ans,x);
        x=mult(x,x);
        n=n/2;
    }
    return ans;
}
int main()
{
    ll x,y,n;
    while(scanf("%lld%lld%lld%lld",&x,&y,&n,&p)!=EOF)
    {
        m.a[0][0]=2*x;m.a[0][1]=y-x*x;
        m.a[1][0]=1;m.a[1][1]=0;
        r=PowerMod(m,n-1);
        ll ans=(r.a[0][0]*2*x+r.a[0][1]*2)%p;
        printf("%lld\n",ans);
    }
    return 0;
}
HDU5451

题意:

给出x和一个质数M,,求。其中

思路:

类似上题的方法,根据特征方程可以求出递推公式为

已知数列满足,其中为常数,且

定理1:方程为该式的特征的特征方程,该方程的根称为的特征根,记为

定理2:若,则,其中为常数,且满足

定理3:若,则,其中为常数,且满足

由定理2,得到通项

因为,因的整数部分为

指数是非常大,但模数,所以可以直接暴力找循环节。

还有一个结论,对于广义斐波那契数列

f(n)%p循环节:当c是模p的二次剩余,枚举的因子,        当c是模p的非二次剩余,枚举的因子。

什么叫二次剩余呢?

d是模p的二次剩余当且仅当

d是模p的非二次剩余当且仅当

假设MOD为模数,则在时,一定为其一个循环节。

在这里循环节可以直接算出,循环节为

代码:

typedef long long ll;
ll f[100010];
ll l[100010];
int init(ll m)
{
    f[0]=2%m,f[1]=10%m;
    for(int i=2;;i++)
    {
        f[i]=(10*f[i-1]-f[i-2]+m)%m;
        //if(i<=10)printf("%lld ",f[i]);
        if(f[i-1]==f[0]&&f[i]==f[1])
            return i-1;
    }
    //printf("\n");
}
long long PowerMod(long long a,long long b,long long c)
{
    long long ans=1;
    long long k;
    k=a;
    k=k%c;
    while(b>0)
    {
        if(b&1)
        ans=(ans*k)%c;
        b>>=1;
        k=(k*k)%c;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int kase=1;kase<=t;kase++)
    {
        ll x,m;
        scanf("%lld%lld",&x,&m);
        int len=init(m);
        //printf("%d\n",len);
        int p=PowerMod(2,x,len);
        //printf("p:%d\n",p);
        printf("Case #%d: %lld\n",kase,(f[(p+1)%len]-1+m)%m);
    }
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

HDU6333 推导+莫队算法 Previous
HDU6219 思维+单调队列 Next