题解 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;
}
posted @ 2022-01-06 21:37  Administrator-09  阅读(0)  评论(0编辑  收藏  举报