http://acm.hdu.edu.cn/showproblem.php?pid=4565
注意取值范围:
0<a,m<215,(a−1)2<b<a2,0<b,n<231
0
<
a
,
m
<
2
15
,
(
a
−
1
)
2
<
b
<
a
2
,
0
<
b
,
n
<
2
31
那么
b√
b
的取值范围就是
(a−1)<b√<a
(
a
−
1
)
<
b
<
a
那么
a−b√
a
−
b
的取值范围就是
(0,1)
(
0
,
1
)
,这个性质我们可以加以利用
(a+b√)n+(a−b√)n
(
a
+
b
)
n
+
(
a
−
b
)
n
展开后会发现答案将是一个整数
而题目正好要求的是向上取整,那么其实这两个式子的答案可以说是相同了。
即
⌈(a+b√)n⌉=(a+b√)n+(a−b√)n
⌈
(
a
+
b
)
n
⌉
=
(
a
+
b
)
n
+
(
a
−
b
)
n
令
Sn=(a+b√)n+(a−b√)n
S
n
=
(
a
+
b
)
n
+
(
a
−
b
)
n
则有
Sn∗[(a+b√)+(a−b√)]=Sn+1+Sn−1∗(a2−b)
S
n
∗
[
(
a
+
b
)
+
(
a
−
b
)
]
=
S
n
+
1
+
S
n
−
1
∗
(
a
2
−
b
)
即
Sn+1=Sn∗[(a+b√)+(a−b√)]+Sn−1∗(b−a2)
S
n
+
1
=
S
n
∗
[
(
a
+
b
)
+
(
a
−
b
)
]
+
S
n
−
1
∗
(
b
−
a
2
)
那么就可以构造矩阵了
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int maxn=1e6+10;
ll a,b,n,mod;
struct mat{
ll p[2][2];
};
mat mul(mat x,mat y);
mat qkm(mat x,ll y);
int main()
{
while(~scanf("%lld %lld %lld %lld",&a,&b,&n,&mod)){
mat x;mat y;
memset(x.p,0,sizeof x.p);
memset(y.p,0,sizeof y.p);
x.p[0][0]=2*a%mod;
x.p[0][1]=1;
x.p[1][0]=((b-a*a)%mod+mod)%mod;
x.p[1][1]=0;
x=qkm(x,n-1);
printf("%lld\n",x.p[0][1]%mod);
}
return 0;
}
mat mul(mat x,mat y){
mat z;
memset(z.p,0,sizeof z.p);
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
z.p[i][j]+=x.p[i][k]*y.p[k][j];
z.p[i][j]%=mod;
(z.p[i][j]+=mod)%mod;
}
}
}
return z;
}
mat qkm(mat x,ll y){
mat ans;
(ans.p[0][0]=(2*(a*a+b))%mod+mod)%=mod;
(ans.p[0][1]=(2*a)%mod+mod)%=mod;
while(y>0){
if(y%2){
ans=mul(ans,x);
}
x=mul(x,x);
y>>=1;
}
return ans;
}