Snail Alice HDU - 3411

本文介绍了一道经典算法竞赛题目HDU-3411 SnailAlice的解决方法,通过分析题目要求计算特定递推式的值,采用矩阵快速幂算法来高效解决大规模数据输入的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Snail Alice  HDU - 3411 


A function f(n), n is a positive integer, and


Given q and n, please calculate the value of f(n).Please note that q and n could be huge.

Input

Input consists of multiple test cases, and ends with a line of “-1 -1 -1”.
For each test case:
The first line contains three integers x1, y1 and z1, representing q. q=x1^y1+z1.
The second line contains two integers: y2 and z2, representing n. n=2^y2+z2.
The third line contains a single integer P, meaning that what you really should output is the formula’s value mod P.
Note: 0<=x1,y1,z1,y2,z2<=50000, z1>0, 0<P<100000000

Output

For each test case, print one line containing an integer which equals to the formula’s value mod P.

Sample Input

2 1 3
0 0
32551
3 0 5
0 2
70546
-1 -1 -1

Sample Output

31


题目太长,所以缩减了一下,题意就是求  上面的那个式子。


思路:  看数据范围,直接求肯定不可能,那么先假定 q 为一个比较小的数,然后 以  n打表,找出递推式,

就有  f(n )=(q-1)f(n-1)+qf(n-2);然后求递推式就是矩阵快速幂了,

  

 但是  n 非常大  (n=2^y2+z2) ,又

 据矩阵快速幂,对于指数的二进制是1 的,需要将底数跟答案相乘,如果为0 的,则不需要。

 那么直接考虑  n-1  ,(2^y2-1) +z2  ,

 可以分两步计算,先算出 q^z2,直接快速幂,再算前面的,(2^y2-1)  的二进制全部为1 ,根据上面的性质直接求 解。

 

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<stack>
#include<vector>
#include<algorithm>
#define maxn 10010
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MOD 1000000007
#define ll long long
using namespace std;

int x1,y11,z1;
int y2,z2;
ll p;
ll Pow(int a,int b,ll mod)
{
    ll ans=1;
    ll aa=a;
    while(b)
    {
        if(b&1) ans=(ans*aa)%mod;
        aa=aa*aa%mod;
        b>>=1;
    }
    return ans%mod;
}
struct Node{

    ll a[3][3];
    void clear()
    {
        memset(a,0,sizeof a);
    }
    friend  Node operator *(Node aa,Node bb);

};
Node operator *(Node aa,Node bb)
{
    Node ans;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            ans.a[i][j]=0;
            for(int k=0;k<2;k++)
            {
                ans.a[i][j]+=aa.a[i][k]*bb.a[k][j];
            }
            ans.a[i][j]%=p;
        }
    }
    return ans;
}
int main()
{
    while(scanf("%d%d%d",&x1,&y11,&z1)!=EOF)
    {
        if(x1==-1&&y11==-1&&z1==-1)
            break;
        scanf("%d%d",&y2,&z2);
        scanf("%lld",&p);
        ll q=(ll)(Pow(x1,y11,p)+z1)%p;
        Node s,b,m;
        s.clear(); m.clear();b.clear();
        s.a[0][0]=(q-1+p)%p;
        s.a[0][1]=q;
        s.a[1][0]=1;
        s.a[1][1]=0;
        b.a[0][0]=1;
        b.a[1][0]=0;
        m=s;
        while(z2)
        {
            if(z2&1)
                b=m*b;
            z2>>=1;
            m=m*m;
        }
        for(int i=0;i<y2;i++)
        {
            b=s*b;
            s=s*s;
        }
        printf("%lld\n",b.a[0][0]);
    }
    return 0;
}





对于上面 的那个快速幂的性质的解释:

其实在写 快速幂的时候就已经运用了:

{...  if(b&1) ...}

详细解释: 

进行快速幂时可以发现,进行的是移位运算,对于指数某一位是1的,就让答案和底数相乘一次,因此模拟y2位的矩阵快速幂,然后再进行z2次快速幂即可。例如2^10, 10的二进制表示 1010 

n=2,m=10,b=1;

1、(1&0==0)  m=m>>1=101,n=n*n=4
2、(1&1==1)   b=b*n=4,m=m>>1=10,n=n*n=16 
3、(0&1==0)  m=m>>1=1,n=n*n=16*16  
4、(1&1==1)  b=b*n=4*16*16 m=m>>1=0 n=n*n; break;

  from  点击打开链接






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值