hdu 3411 推公式+矩阵快速幂

其实这题也算是看解题报告练得一题,不过还是很有收获的。

碰到这种求大数函数值时,果断最先想到矩阵快速幂。。。把f(x)写成递推公式的形式。问题是这个函数还来个大括号,还要讨论,咋搞?

首先是对公式的处理(⊙﹏⊙b汗,就是这步想不到,所以果断看来解题报告),直接多项式除法(orz.....算是真心长姿势了),得出f(n)=x^(n-1)-x^(n-2)+....+1(n为奇数),f(n)=x^(n-1)-x^(n-2)+...x-1(n为偶数),这就看出规律了,f(n)=q*f(x-1)+1(n为奇数),f(n)=q*f(x-1)-1(n为偶数)。先看当n为奇数时的情况,这个+1是个碍事的东西,怎么办?其实稍加改变就OK了(我看的某份结题报告竟然是硬推!!!这个其实并不好)把f(n)改写成f(n)=(q-1)f(x-1)+f(x-1)-1=(q-1)f(x-1)+x^(n-1)-x^(n-2)+...+x-1+1=(q-1)f(x-1)+qf(x-2)。。。当n为偶数时,也是类似的,也能推出此公式,过程略掉。。。。哈哈,搞定。。然后矩阵快速幂就OK了。。这题时间卡的太狠,本人代码挫出翔,竟然是过这题当中时间最慢的(。。。。。),用C++才能过,G++跪。。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>

#define N 50005
#define M 30
#define read(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define cl(a) memset(a,0,sizeof(a))
#define ll long long

ll x[M],f[3],r[N][3][3],q;
int p;
 
using namespace std;

ll bin(ll t)
{
    ll res=1;
    int i=0;
    while (t>0)
    {
        if (t&1) res=(res*x[i])%p;
        i++;
        t>>=1;
    }
    return res;
}

void init()
{
    r[0][1][1]=(q-1+p)%p;
    r[0][1][2]=q;
    r[0][2][1]=1;
    r[0][2][2]=0;
    f[1]=1;f[2]=0;
}

void mul(int t)
{
    int i,j,k;
    for (i=1;i<=2;i++)
        for (j=1;j<=2;j++)
        {
            r[t][i][j]=0;
            for (k=1;k<=2;k++) r[t][i][j]=r[t][i][j]+(r[t-1][i][k]*r[t-1][k][j])%p; 
        }
}

void zmul(int i)
{
    ll g1,g2;
    g1=(f[1]*r[i][1][1])%p+(f[2]*r[i][1][2])%p;
    g2=(f[1]*r[i][2][1])%p+(f[2]*r[i][2][2])%p;
    f[1]=g1%p;f[2]=g2%p;
}

void bin2(int t)
{
    int i=0;
    while (t>0)
    {
        if (t&1) zmul(i);
        t>>=1;
        i++;
    }   
}

int main()
{
    int x1,y1,z1,y2,z2,i,j;
    while (read(x1,y1,z1)!=EOF)
    {
        if (x1==-1&&y1==-1&&z1==-1) break;
        read(y2,z2,p);
        cl(x);
        x[0]=x1%p;
        for (i=1;i<M;i++) x[i]=(x[i-1]*x[i-1])%p;
        q=(bin(y1)+z1)%p;
        init();
        for (i=1;i<N;i++) mul(i);
        zmul(y2);
        if (z2>0) bin2(z2-1);
        if (z2>=1) printf("%d\n",f[1]);
        else printf("%d\n",f[2]);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值