[BZOJ2875] [NOI2012] 随机数生成器 [快速幂&分治&乘法取模]

[ L i n k \frak{Link} Link]


我建议去洛谷看题面((


就是说 x n ≡ a n x 0 + ∑ i = 0 n − 1 a i c ( m o d m ) x_n\equiv a^nx_0+\sum\limits_{i=0}^{n-1}a^ic\pmod{m} xnanx0+i=0n1aic(modm)
感觉可以直接球?? x n = ( a n x 0 + ∑ i = 0 n − 1 a i c ) % m = [ ( a n x 0 ) + ( a n − 1 ) c a − 1 ] % m x_n=(a^nx_0+\sum\limits_{i=0}^{n-1}a^ic)\%m=\left[(a^nx_0)+\frac{(a^n-1)c}{a-1}\right]\%m xn=(anx0+i=0n1aic)%m=[(anx0)+a1(an1)c]%m
快速幂 a n a^n an ,然后逆元就可以啦。是吗?

这个逆元不一定存在吧。所以要暴力分治做等比数列求和 + 取模。
注意最后要输出 x n % g x_n\%g xn%g

注意: x % a % b x\%a\%b x%a%b 并不总是等于 x % b % a x\%b\%a x%b%a 。也就是说不能快乐全程 % g % m \%g\%m %g%m
计算 x n x_n xn 的时候只能 % m \%m %m ,计算出来了才能 % g \%g %g
这就带来了一个问题,这样爆 long long 很大力啊?
解决方法:用龟速乘法,类似于快速幂那样拆乘法取模。。。

当然,也可以用矩阵快速幂加速递推……随意啦。反正挺沙雕的。

我怎么感觉 BZOJ 评测比洛谷快了x


#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
unsigned long long m, a, c, x, n, g, t;
unsigned long long mul(unsigned long long a, unsigned long long b)
{
	unsigned long long ret = 0;
	while(b)
	{
		if (b & 1)
		{
			ret += a;
			ret %= m;
		}
		a += a;
		a %= m;
		b >>= 1;
	}
	return ret;
}
unsigned long long qpow(unsigned long long base, unsigned long long ind)
{
	base %= m;
	unsigned long long ans = 1;
	while (ind)
	{
		if (ind & 1)
		{
			ans = mul(ans, base);
		}
		base = mul(base, base);
		ind >>= 1;
	}
	return ans;
}
unsigned long long qsum(long long N)
{
	if (N <= 1) return 1;
	unsigned long long fafa = mul(qsum(N >> 1), (qpow(a, N >> 1) + 1));
	if (N & 1 == 1) fafa += qpow(a, N - 1);
	return fafa % m;
}
int main()
{
	scanf("%lld%lld%lld%lld%lld%lld", &m, &a, &c, &x, &n, &g);
	t = mul(qpow(a, n), x) % m;
	t += mul(qsum(n), c) % m;
	printf("%lld", t % m % g);
	return 0;
}

后面是我这个菜鸡补小学奥数的一点记录(
与这道大氵题无关。


费马小定理:对于质数 p p p 和整数 a < p a<p a<p a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod{p} ap11(modp)

证明:构建 p p p 的完全剩余系 P = { 1 , 2 , ⋯   , p − 1 } P=\{1,2,\cdots,p-1\} P={1,2,,p1} ( a , p ) = 1 (a,p)=1 (a,p)=1
那么 A = { a , 2 a , ⋯   , ( p − 1 ) a } A=\{a,2a,\cdots,(p-1)a\} A={a,2a,,(p1)a} 也是 p p p 的完全剩余系。
所以 ( p − 1 ) ! ≡ ( p − 1 ) ! a p − 1 ( m o d p ) (p-1)!\equiv(p-1)!a^{p-1}\pmod{p} (p1)!(p1)!ap1(modp) ,又 ( ( p − 1 ) ! , p ) = 1 \left((p-1)!,p\right)=1 ((p1)!,p)=1 显然可以得证。

同时,不论 a a a 是否小于 p p p 都有 a p ≡ a ( m o d p ) a^p\equiv a\pmod{p} apa(modp)

利用这个可以求整数 a < p a<p a<p 在模质数 p p p 意义下的逆元 a p − 2 ( m o d p ) a^{p-2}\pmod{p} ap2(modp)


贝祖定理

  1. ( a , b ) ∣ ( a x + b y ) (a,b)|(ax+by) (a,b)(ax+by)
  2. 一定存在 x , y x,y x,y 满足 a x + b y = ( a , b ) ax+by=(a,b) ax+by=(a,b)

一个重要推论: ∃ a , b , a x + b y = 1 \exists a,b,ax+by=1 a,b,ax+by=1 ( a , b ) = 1 (a,b)=1 (a,b)=1 的充要条件。


GCD:当 a a a k b , k ∈ N ∗ kb,k\in\N^* kb,kN ( a , b ) = ( a % b , b ) (a,b)=(a\%b,b) (a,b)=(a%b,b) 。以及一段代码 !b?a:gcd(b,a%b)

为什么代码里面要 b,a%b
因为如果写成 a%b,b ,当 a < b a<b a<b 时就可能无限循环了。交换一下就可以解决。

证明:显然有 ( a , b ) ∣ b (a,b)|b (a,b)b 没错吧??
先假设 a > b a>b a>b
我们设 a = k b + r a=kb+r a=kb+r
因为 ( a , b ) ∣ k b (a,b)|kb (a,b)kb 而且 ( a , b ) ∣ a (a,b)|a (a,b)a
那么 ( a , b ) ∣ k b (a,b)|kb (a,b)kb 而且 ( a , b ) ∣ ( k b + r ) (a,b)|(kb+r) (a,b)(kb+r)
显然 ( a , b ) ∣ r (a,b)|r (a,b)r
而且 r = a % b r=a\%b r=a%b 显然啦。


ExGCD ( a , b ) = a x + b y (a,b)=ax+by (a,b)=ax+by 然后我们求 x x x y y y

b = 0 b=0 b=0 x = 1 , y = 0 x=1,y=0 x=1,y=0 。这个特殊情况不能用。

b b b 0 0 0,我们仍然假设 a > b a>b a>b 。对于每次 ( a , b ) (a,b) (a,b) ( b , a % b ) (b,a\%b) (b,a%b) 过程中 x , y x,y x,y 的变化:
a x 1 + b y 1 = ( a , b ) = ( b , a % b ) = b x 2 + ( a % b ) y 2 ax_1+by_1=(a,b)=(b,a\%b)=bx_2+(a\%b)y_2 ax1+by1=(a,b)=(b,a%b)=bx2+(a%b)y2
a = k b + r a=kb+r a=kb+r 。有 a x 1 + b y 1 = b x 2 + ( a − k b ) y 2 ax_1+by_1=bx_2+(a-kb)y_2 ax1+by1=bx2+(akb)y2
我们记 a / b = ⌊ a b ⌋ a/b=\lfloor\frac{a}{b}\rfloor a/b=ba 那么 a x 1 + b y 1 = b x 2 + a y 2 − ( a / b ) ⋅ b y 2 ax_1+by_1=bx_2+ay_2-(a/b)\cdot by_2 ax1+by1=bx2+ay2(a/b)by2
a x 1 + b y 1 = a y 2 + b [ x 2 − ( a / b ) y 2 ] ax_1+by_1=ay_2+b[x_2-(a/b)y_2] ax1+by1=ay2+b[x2(a/b)y2] 所以 x 1 = y 2 , y 1 = [ x 2 − ( a / b ) y 2 ] x_1=y_2,y_1=[x_2-(a/b)y_2] x1=y2,y1=[x2(a/b)y2]
这样的话就可以从 b = 0 b=0 b=0 的时候开始一路倒推直到 a , b a,b a,b 都是原来的样子。

就可以得到原方程 a x + b y = ( a , b ) ax+by=(a,b) ax+by=(a,b) 的一组解。


ExGCD 解不定方程 a x + b y = c ax+by=c ax+by=c

显然 ( a , b ) ∣ c (a,b)|c (a,b)c 才有解。
否则……那不就随便解解嘛,不讲了?细节自己草稿纸吧。

也需要稍微说一下通解的形式:设 r = ( a , b ) r=(a,b) r=(a,b) ,对于 a x + b y = r ax+by=r ax+by=r 如果有一组解 x 0 , y 0 x_0,y_0 x0,y0
显然 a ⋅ [ x ± ( b / r ) ] + b ⋅ [ y ∓ ( a / r ) ] = r a\cdot[x\pm (b/r)]+b\cdot[y\mp(a/r)]=r a[x±(b/r)]+b[y(a/r)]=r
于是通解的形式是 x = x 0 ± b / r , y = y 0 ∓ ( a / r ) x=x_0\pm b/r,y=y_0\mp(a/r) x=x0±b/r,y=y0(a/r)

启发这个想法的是把 x 0 , y 0 x_0,y_0 x0,y0 改动后保持等价,显然可以凑 a ( x 0 + b ) + b ( y 0 − a ) = r a(x_0+b)+b(y_0-a)=r a(x0+b)+b(y0a)=r
要在保证 x , y x,y x,y 是整数的前提下表示出尽量多的解,所以就变成 b / r b/r b/r a / r a/r a/r 啦。


ExGCD 解线性同余方程 a x ≡ c ( m o d b ) ax\equiv c\pmod{b} axc(modb)

转化: a x % b = c % b ax\%b=c\%b ax%b=c%b
转化化: a x + b μ = c + b λ ax+b\mu=c+b\lambda ax+bμ=c+bλ
转化化化: a x + b y = c ax+by=c ax+by=c
解出 x 0 x_0 x0 ,设 s = b / r s=b/r s=b/r ,然后最小正整数解 ( x 0 % s + s ) % s (x_0\%s+s)\%s (x0%s+s)%s

为什么最小整数解是这个?……你认真的?
……里面模一次,得到的不一定是正数,加上 s s s 再模一次得到正数。
PS:C艹的取模是向零取整的,无论正负。


ExGCD求逆元

就是上面那个啊。

你可能感兴趣的:(BZOJ,分治,快速幂,乘法取模)