题解:AT_arc050_c [ARC050C] LCM 111

arc050c 解题报告

前言

这里提供一种矩阵乘法做法。

问就是因为根本看不懂现有的一篇题解。

思路分析

首先因为 lcm 没什么好的性质,考虑转化为 gcd 求解。

\(f_i\) 表示 \(i\)\(1\) 拼接形成的数。

所以我们实际上要求 \(\frac{f_a\cdot f_b}{\gcd(f_a,f_b)}\)

开始发掘性质了。

性质 1

\[\gcd(f_a,f_b)=f_{\gcd(a,b)} \]

考虑证明。

钦定 \(a\ge b\),根据更相减损术,有:

\[\gcd(f_a,f_b)=\gcd(f_a-f_b,f_b)=\gcd(10^bf_{a-b},f_b) \]

因为 \(f_b\) 不是 \(2\)\(5\) 的因数,所以:

\[\gcd(f_a,f_b)=\gcd(f_{a-b},f_b) \]

同理可以将减法推广:

\[\gcd(f_a,f_b)=\gcd(f_{a\bmod b},f_b) \]

利用辗转相除法求到边界情况:

\[\gcd(f_a,f_b)=\gcd(f_{\gcd(a,b)},f_0)=f_{\gcd(a,b)} \]

证毕。

性质2

\(b\mid a\) 时,\(\frac{f_a}{f_b}\) 形如:\(100\cdots0100\cdots0100\cdots01\),其中 \(00\cdots01\) 周期长度为 \(b\),周期个数为 \(\frac{a}{b}\)

证明显然,不再赘述。

其实打个表也能看出来。

有了这两个性质,这个题就好做了。

\(g_{i,j}\) 表示 \(00\cdots01\) 的周期长度为 \(i\),周期个数为 \(j\),那么 \(\frac{f_a\cdot f_b}{\gcd(f_a,f_b)}=g_{\gcd(a,b),\frac{a}{\gcd(a,b)}}\cdot g_{1,b}\)

然后考虑 \(g\) 的递推。不难发现:

\[g_{i,j}=10^jg_{i,j-1}+1 \]

这肯定可以矩阵加速。

设初始矩阵为:

\[\begin{bmatrix} g_{i,j}& g_{i,j-1} & 1 \end{bmatrix}\]

转移矩阵为:

\[\begin{bmatrix} 10^i& 1& 0\\ 0& 0& 0&\\ 1& 0& 1 \end{bmatrix}\]

做完了。

总体复杂度为 \(O(\log v)\)。有些常数。

代码实现

#include<bits/stdc++.h>
#define int long long
using namespace std; 
int x,y,mod;
struct node{
	long long h[4][4];
	node(){
		memset(h,0,sizeof(h));
	}
	node operator *(const node &a)const{
		node ans;
		for(int i=1;i<=3;i++){
			for(int j=1;j<=3;j++){
				for(int k=1;k<=3;k++){
					ans.h[i][j]=(ans.h[i][j]+h[i][k]*a.h[k][j]%mod)%mod;
				}
			}
		}
		return ans;
	}
}a,b,c;
node binpow(node a,int b){
	if(b==0) return c;
	node res=binpow(a,b/2);
	if(b&1) return (res*res)*a;
	else return res*res;
}
int qpow(int a,int b){
	if(b==0) return 1;
	int res=qpow(a,b/2);
	if(b&1) return res*res%mod*a%mod;
	else return res*res%mod;
}
int f(int x,int len,int tim){
	if(tim==1) return 1;
	if(tim==2) return qpow(10,len)+1;
	a.h[1][1]=qpow(10,len)+1;
	a.h[1][2]=1;
	a.h[1][3]=1;
	b.h[1][1]=qpow(10,len);
	b.h[1][2]=1;
	b.h[3][1]=1;
	b.h[3][3]=1;
	c.h[1][1]=1;
	c.h[2][2]=1;
	c.h[3][3]=1;
	a=a*binpow(b,tim-2);
	return a.h[1][1];
}
signed main(){
	cin>>x>>y>>mod;
	cout<<f(x,__gcd(x,y),x/__gcd(x,y))*f(y,1,y)%mod<<'\n';
	return 0;
}

后记

祝 CSP2024 rp++

posted @ 2025-01-24 16:44  _Kenma  阅读(22)  评论(0)    收藏  举报