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
1
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
from 點擊打開鏈接