题解 B君的回忆
整个题解里没有严谨证明的地方……记一下做法好了
发现当 \(k\geqslant 2\) 的时候需要找到矩阵乘的循环节
也就是求 \(a^x\equiv a \pmod p\)
于是bsgs求一下
发现T了
首先 \(f(p_i^{c_i}p_j^{c_j})=lcm(f(p_i^{c_i}), f(p_j^{c_j}))\) 还是比较可证的
然后结论 \(f(p_i^{c_i})=f(p_i)p_i^{c_i-1}\) 目前还不理解
把矩阵hash了暴力一点处理就可以了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define ull unsigned long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
ll a, b, n, k, p, mod, prd;
int divd[N], c[N], top;
unordered_map<ll, ll> mp2;
struct matrix{
int n, m;
ll a[5][5];
matrix(){}
matrix(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
inline void resize(int x, int y) {n=x; m=y; memset(a, 0, sizeof(a));}
inline ll* operator [] (int t) {return a[t];}
inline ull hashme() {ull ans=0; for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) ans=ans*13131+a[i][j]; return ans;}
inline void put() {for (int i=1; i<=n; ++i) {for (int j=1; j<=m; ++j) cout<<setw(3)<<a[i][j]<<' '; cout<<endl;} cout<<endl;}
inline matrix operator * (matrix b) {
matrix ans(n, b.m);
for (int i=1; i<=n; ++i)
for (int k=1; k<=b.m; ++k)
for (int j=1; j<=m; ++j)
ans[i][k]=((ans[i][k]+a[i][j]*b[j][k])%mod+mod)%mod;
return ans;
}
}mat, tr;
inline matrix qpow(matrix a, ll b) {matrix ans=a; --b; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
inline bool operator == (matrix a, matrix b) {
if (a.n!=b.n||a.m!=b.m) return 0;
for (int i=1; i<=a.n; ++i)
for (int j=1; j<=a.m; ++j)
if (a[i][j]!=b[i][j]) return 0;
return 1;
}
struct matrix_hash{inline size_t operator () (matrix a) const {return hash<ull>()(a.hashme());}};
unordered_map<matrix, ll, matrix_hash> mp{5000, matrix_hash()};
inline ll qpow(ll a, int b) {ll ans=1; for (; b; a=a*a,b>>=1) if (b&1) ans=ans*a; return ans;}
inline ll gcd(ll a, ll b) {return !b?a:gcd(b, a%b);}
inline ll lcm(ll a, ll b) {return a/gcd(a, b)*b;}
ll g(ll n, ll p) {
if (!n) return a;
if (n==1) return b;
mod=p;
mat.resize(1, 2); tr.resize(2, 2);
mat[1][1]=a; mat[1][2]=b;
tr[1][1]=0; tr[1][2]=-1; tr[2][1]=1; tr[2][2]=3;
mat=mat*qpow(tr, n-1);
return (mat[1][2]%p+p)%p;
}
ll qprd(const matrix& a, ll p) {
// cout<<"qprd: "<<p<<endl;
if (mp2.find(p)!=mp2.end()) return mp2[p];
mp.clear();
ll m=ceil(sqrt(3*p));
// cout<<"m: "<<m<<endl;
matrix t=a, t2;
mod=p;
for (int j=0; j<=m; ++j) mp[t]=j, t=t*a; //, t.put();
t=t2=qpow(a, m);
// t.put();
for (int i=1; i<=m; ++i) {
// cout<<"i: "<<i<<endl;
// t.put();
if (mp.find(t)!=mp.end()&&i*m-mp[t]!=1) return mp2[p]=i*m-mp[t]-1;
t=t*t2;
}
cerr<<"qprd: "<<p<<endl;
assert(0);
}
void divide(ll mod) {
ll n=mod; top=0;
for (int i=2; i*i<=n; ++i) if (n%i==0) {
divd[++top]=i; c[top]=0;
do {n/=i; ++c[top];} while (n%i==0);
}
if (n>1) divd[++top]=n, c[top]=1;
}
ll f(ll n, ll k, ll p) {
// cout<<"f: "<<n<<' '<<k<<' '<<p<<endl;
if (k==1) return g(n, p);
divide(p);
// cout<<"div: "; for (int i=1; i<=top; ++i) cout<<"("<<divd[i]<<','<<c[i]<<")"<<' '; cout<<endl;
// cout<<"prd: "; for (int i=1; i<=top; ++i) cout<<qprd(tr, divd[i])<<' '; cout<<endl;
ll prd=1;
for (int i=1; i<=top; ++i) prd=lcm(prd, qprd(tr, divd[i])*qpow(divd[i], c[i]-1));
// cout<<"prd: "<<prd<<endl;
return g(f(n, k-1, prd), p);
}
signed main()
{
int T=read();
while (T--) {
a=read(); b=read(); n=read(); k=read(); p=read();
tr.resize(2, 2);
tr[1][1]=0; tr[1][2]=-1; tr[2][1]=1; tr[2][2]=3;
// divide(p);
// prd=1;
// cout<<"div: "; for (int i=1; i<=top; ++i) cout<<"("<<divd[i]<<','<<c[i]<<")"<<' '; cout<<endl;
// cout<<"prd: "; for (int i=1; i<=top; ++i) cout<<qprd(tr, divd[i])<<' '; cout<<endl;
// for (int i=1; i<=top; ++i) prd=lcm(prd, qprd(tr, divd[i])*qpow(divd[i], c[i]-1));
// cout<<"prd: "<<prd<<endl;
printf("%lld\n", f(n, k, p));
}
// mod=13;
// tr.resize(2, 2);
// tr[1][1]=0; tr[1][2]=-1; tr[2][1]=1; tr[2][2]=3;
// mat=tr;
// for (int i=1; i<=25; ++i) {
// cout<<"i: "<<i<<endl;
// tr.put();
// tr=tr*mat;
// }
// qpow(mat, 7).put();
return 0;
}