题目链接: HDU6956 Pass!
题目大意: 有n个人互相传球,一开始球在一号脚下,设 t t t轮过后,球传到一号的方案数为 x x x,现在给出 x x x求 t t t。
题目分析: 容易得出递推方程
f
[
i
]
[
0
]
=
f
[
i
−
1
]
[
1
]
∗
(
n
−
1
)
+
f
[
i
−
1
]
[
0
]
∗
(
n
−
2
)
f[i][0]=f[i-1][1]*(n-1)+f[i-1][0]*(n-2)
f[i][0]=f[i−1][1]∗(n−1)+f[i−1][0]∗(n−2)
f
[
i
]
[
1
]
=
f
[
i
−
1
]
[
0
]
f[i][1]=f[i-1][0]
f[i][1]=f[i−1][0]其中
f
[
i
]
[
0
]
f[i][0]
f[i][0]表示在第
i
i
i轮中球在第一个人脚下,
f
[
i
]
[
1
]
f[i][1]
f[i][1]表示不在
整个式子就可以写为
f
(
i
)
=
f
(
i
−
1
)
∗
(
n
−
2
)
+
f
(
i
−
2
)
∗
(
n
−
1
)
f(i)=f(i-1)*(n-2)+f(i-2)*(n-1)
f(i)=f(i−1)∗(n−2)+f(i−2)∗(n−1)根据递推式的特征方程设
f
(
i
)
f(i)
f(i)的特征方程为
x
2
−
(
n
−
2
)
x
−
(
n
−
1
)
=
0
x^2-(n-2)x-(n-1)=0
x2−(n−2)x−(n−1)=0带入
f
(
0
)
=
1
,
f
(
1
)
=
0
f(0)=1,f(1)=0
f(0)=1,f(1)=0 得
f
(
i
)
=
(
n
−
1
)
∗
(
−
1
)
i
+
(
n
−
1
)
i
n
m
o
d
998244353
f(i)=\frac{(n-1)*(-1)^i+(n-1)^i}{n}mod998244353
f(i)=n(n−1)∗(−1)i+(n−1)imod998244353现在
f
(
i
)
f(i)
f(i)已知将式子变形后分奇偶讨论求离散对数即可。
题目代码:
#include<bits/stdc++.h>
#define mxn 1000005
#define mod 998244353
#define LL long long
#pragma GCC optimize(2)
using namespace std;
unordered_map<LL,LL>x;
inline int Read(){
register int ret=0;register char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=(ret<<1)+(ret<<3)+(c^48),c=getchar();
return ret;
}
inline LL ksm(register LL x,register LL y){
return y?(y&1?x*ksm(x,y-1)%mod:ksm(x*x%mod,y/2)):1;
}
inline LL log_mod(register LL a,register LL b){
register LL m,v,e=1;
m=(LL)sqrt(mod+0.5);
v=ksm(ksm(a,m),mod-2);
x.clear();
x[1]=0;
for(register LL i=1;i<m;i++){
e=e*a%mod;
if(!x.count(e))x[e]=i;
}
for(register LL i=0;i<m;i++){
if(x.count(b))return i*m+x[b];
b=b*v%mod;
}
return -1;
}
int main()
{
//freopen("G.in","r",stdin);
//freopen("G.out","w",stdout);
register int t;
register LL k,x;
scanf("%d",&t);
while(t--){
k=Read();
x=Read();
register LL a=k-1;
register LL b=(k-1+k*x%mod+mod)%mod;
register LL ans=log_mod(a,b);
b=(k*x%mod-k+1+mod)%mod;
register LL _ans=log_mod(a,b);
if(ans%2==0) ans=-1;
if(_ans%2==1) _ans=-1;
if(ans==-1){
printf("%lld\n",_ans);
continue;
}
if(_ans==-1){
printf("%lld\n",ans);
continue;
}
printf("%lld\n",min(ans,_ans));
}
return 0;
}