「WC2021」斐波那契
题目
点这里看题目。
分析
有点厉害啊......
首先注意到,由于递推关系和询问参数 \(a,b\) 没有关系,我们可以使用斐波那契数列 \(f\) 来给出 \(F\) 的“通项”。换言之,也就是:
Note.
简单的理解方法:考虑转移矩阵的幂次 \(\begin{bmatrix}1&1\\1&0\end{bmatrix}^n=\begin{bmatrix}f_n&f_{n-1}\\ f_{n-1}&f_{n-2}\end{bmatrix}\)。
这里,我们允许 \(f\) 出现负下标。负下标的情况可以由递推式给出:
\[f_{n-2}=f_{n}-f_{n-1},n\le 1 \]比如,有 \(f_{-1}=0,f_{-2}=1\)。
去掉一些容易处理的边界,我们现在考虑 \(a,b,b-a\not\equiv 0\pmod m\) 的情况。所以,我们只需要解决:
先做一点显然的处理:对于 \(u,v,m\) 同时除掉 \(\gcd(u,v,m)\),得到 \(u',v',m'\)。
如果有着良好的互质性,比如 \(m'\) 是一个质数,那么接下来我们可以直接将 \(f\) 和 \(u,v\) 分开,从而做一些预处理。不过,虽然 \(\gcd(u',v',m')=1\),我们却还无法保证 \(u'\perp m'\) 或者 \(v'\perp m'\),因此还需要再做尝试。
很容易想到把 \(\gcd(u',m')\) 和 \(\gcd(v',m')\) 给除掉。但是怎么保证除了之后不会出现分数?结合我们的目的和斐波那契自身的性质 \(f_{n-1}\perp f_n\),我们不难猜到这样一个结论:
为了节约篇幅,证明缩在了这里:
Proof.
刚拿到这个条件的时候,我们注意到:同余条件可以产生 \(\gcd\),而反过来比较困难。因此,我们选择将仅有的同余式转化成 \(\gcd\) 的关系:
\[\gcd(u'f_n,m')=\gcd(v'f_{n-1},m')=a \]把 \(a\) 除到 \(\gcd\) 里面去,并考虑 \(a\) 是如何“分配”而来的。也就是说:
\[\begin{aligned} &\gcd\left(\frac{u'd_1}{a}\cdot \frac{f_n}{d_1},\frac{m'}{a}\right)\\ =&\gcd\left(\frac{v'd_2}{a}\cdot \frac{f_{n-1}}{d_2},\frac{m'}{a}\right)\\ =&1 \end{aligned} \]这将会给出:
\[\gcd(d_1u',d_2v',m')=a \]由于 \(f_{n-1}\perp f_n\),显然有 \(d_1\perp d_2\)。结合 \(\gcd(u',v',m')=1\),我们可以知道 \(d_1d_2=a\)。此时我们已经完成了 \(d_2|\gcd(u',m')\) 和 \(d_1|\gcd(v',m')\)。
接下来证明 \(\gcd(u',m')=d_2\)。这一点只需要结合 \(\gcd(u'f_n,m')=d_1d_2,d_1\perp d_2\) 即可得到。证明 \(\gcd(v',m')=d_1\) 类似。
所以,这样处理过后我们又将 \(u,v\) 和 \(f\) 分开了。对于每个 \(m'|m\) 我们可以处理出所有可能的三元组 \((d_1,d_2,(f_nd_1^{-1})(f_{n-1}d_2^{-1})^{-1}\bmod (m'd_1^{-1}d_2^{-1}))\)。由于斐波那契的循环节长度是 \(O(m')\) 的,因此对于每个质因子暴力枚举即可。询问直接查一下就结束了。
时间复杂度为 \(O(\sigma (m)\log m+n\log m)\)。
代码
由于我偷懒没有精细实现,这份代码在洛谷上会 TLE,在 LOJ 上才能过
#include <map>
#include <set>
#include <cstdio>
#include <vector>
#include <iostream>
#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )
const int MAXN = 1e6 + 5, MAXD = 2e3 + 5;
template<typename _T>
void read( _T &x ) {
	x = 0; char s = getchar(); bool f = false;
	while( ! ( '0' <= s && s <= '9' ) ) { f = s == '-', s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	if( f ) x = -x;
}
template<typename _T>
void write( _T x ) {
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) write( x / 10 );
	putchar( x % 10 + '0' );
}
struct Triple {
	int a, b, c;
	Triple(): a( -1 ), b( -1 ), c( -1 ) {}
	Triple( int A, int B, int C ): a( A ), b( B ), c( C ) {}
	inline bool operator < ( const Triple &q ) const {
		return a == q.a ? ( b == q.b ? c < q.c : b < q.b ) : a < q.a;
	}
};
std :: set<std :: pair<int, int> > ever;
std :: map<Triple, int> occ[MAXD];
int dvs[MAXD], tot = 0;
int N, M;
inline int Gcd( int x, int y ) { for( int z ; y ; z = x, x = y, y = z % y ); return x; }
inline int Exgcd( const int &a, const int &b, int &x, int &y ) {
	if( ! b ) return x = 1, y = 0, a;
	int d = Exgcd( b, a % b, y, x );
	y -= x * ( a / b ); return d;
}
inline int Inv( const int &a, const int &mod ) {
	static int x, y;
	Exgcd( a, mod, x, y );
	return ( x % mod + mod ) % mod;
}
void Enumerate( const int &mod ) {
	ever.clear();
	dvs[++ tot] = mod;
	int x = 1, y = 0, p, q;
	for( int n = 0 ; ; n ++ ) {
		if( ever.find( { x, y } ) != ever.end() ) break;
		ever.insert( { x, y } );
		p = Gcd( x, mod ), q = Gcd( y, mod );
		Triple nxt( p, q, 1ll * ( y / q ) * Inv( x / p, mod / p / q ) % ( mod / p / q ) );
		if( occ[tot].find( nxt ) == occ[tot].end() )
			occ[tot][nxt] = n;
		y = ( x + y ) % mod, std :: swap( x, y );
	}
}
int main() {
	read( N ), read( M );
	rep( i, 1, M )
		if( M % i == 0 )
			Enumerate( i );
	while( N -- ) {
		int a, b, m = M;
		read( a ), read( b );
		if( a == 0 ) { 
			puts( "0" ); 
			continue; 
		}
		if( b == 0 ) {
			puts( "1" );
			continue;
		}
		b = ( a - b + m ) % m;
		int d = Gcd( Gcd( a, b ), m );
		a /= d, b /= d, m /= d;
		int d1 = Gcd( a, m ), d2 = Gcd( b, m );
		int idx = std :: lower_bound( dvs + 1, dvs + 1 + tot, m ) - dvs;
		Triple qry( d2, d1, 1ll * ( a / d1 ) * Inv( b / d2, m / d1 / d2 ) % ( m / d1 / d2 ) );
		if( occ[idx].find( qry ) == occ[idx].end() ) 
			puts( "-1" );
		else
			write( occ[idx][qry] ), putchar( '\n' );
	}
	return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号