123789456ye

已AFO

xgzc的数论总结

attention

证略

9.14 Day 1

狄利克雷卷积

\[(f×g)(x)=\sum_{d|x}{f(d)g(\frac{x}{d})} \]

满足交换律,数乘结合律,函数结合律,数乘分配律,函数分配律,单位元\(\epsilon(n)=[n==1]\)

莫比乌斯反演

\(f=g×1\)
其中

\[g=f×\mu \\ 1×\mu=\epsilon\]

线性筛

众所周知,线性筛可以筛所有积性函数。
\(f\)为积性函数。
1.求出\(f(1),f(p)\),p 为质数。
2.求出\(f(p^k)\)\(f(p^{k-1})\)的关系。

一个例子

\(f=id^2*\mu\),其中乘号为狄利克雷卷积。

\[\begin{split} & f(1)=1,f(p)=1* \mu(p)+p^2* \mu(1)=p^2-1 \\ & f(p^k)=p^{2* (k-1)}* \mu(p)+p^{2k}* \mu(1)=f(p)* p^{2* (k-1)}=f(p^{k-1})* p^2 \\ \end{split} \]

\[\begin{split} \therefore f(i* p_{j})= \begin{cases} f(i)* p_{j}^2 & if(i \%p_{j}\not=0) \\ f(i)* f(p_{j}) & if(i \% p_{j}=0) \end{cases} \end{split}\]

inline void eular(int x)
{
    for(int i=2;i<=x;++i)
    {
        if(!vis[i]) prime[++cnt]=i,f[i]=i*i-1;
        for(int j=1;j<=cnt&&i*prime[j]<=x;++j)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j])
            {
                f[i*prime[j]]=f[i]*(f[prime[j]]+1);
                continue;
            }
            else
            {
                f[i*prime[j]]=f[i]*f[prime[j]];
                break;
            }
        }
    }
}

一个证明

证明:\(\sum_{i=1}^{n}\sum_{j=1}^{m}f(\gcd(i,j))=\sum_{i=1}^{n}(f×\mu)(i) \left \lfloor \frac{n}{i} \right \rfloor \left \lfloor \frac{m}{i} \right \rfloor\)
  其中\(n\leq m,(f×\mu)(x)=\sum_{i\mid x}{f(i)* \mu(\frac{x}{i})}\)也就是狄利克雷卷积

\[\begin{split} \sum_{i=1}^{n}\sum_{j=1}^{m}f(\gcd(i,j)) & =\sum_{d=1}^{n}\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}{f(d)\sum_{q\mid \gcd(i,j)}\mu(q)} \newline & = \sum_{d=1}^{n}{f(d)* \sum_{q=1}^{\frac{n}{d}}\mu(q)\left \lfloor \frac{n}{dq} \right \rfloor \left \lfloor \frac{m}{dq} \right \rfloor} \newline & = \sum_{dq=1}^{n}{\left \lfloor \frac{n}{dq} \right \rfloor \left \lfloor \frac{m}{dq} \right \rfloor\sum_{q\mid dq}{f(q)\mu(d)}} \newline & = \sum_{i=1}^{n}(f×\mu)(i) \left \lfloor \frac{n}{i} \right \rfloor \left \lfloor \frac{m}{i} \right \rfloor \end{split}\]

魔力筛

考虑你有一个非积性函数 f 。
现在按上面的,你要求\(f×\mu\)(狄利克雷卷积)。
显然你不能线性筛。
一般的暴力是\(O(n\sqrt n)\)的,优化一下能做到\(O(n\log n)\)
然而这个筛是\(O(n\log\log n)\)

\[g_{i,n}=\sum_{d\mid n,d只含前i种质因子}{f(d)\mu(\frac{n}{d})} \]

状态转移为
\begin{cases}
g_{i,n} = g_{i-1,n} & if(n\% p_{i} \not = 0) \newline
g_{i,n} = g_{i-1,n}-g_{i-1,n/p_{i}} & if(i \% p_{j}=0)
\end{cases}

inline void magic() 
{
	for (int i = 1; i <= x; ++i) g[i] = f[i];
	for (int i = 1; i <= primecnt; ++i)
		for (int j = x / prime[i]; j ; --j)
			g[j * prime[i]] = (g[j * prime[i]] - g[j]) % mod;
}

9.17 Day 2

扩展欧拉定理

\[\begin{split} a^b\equiv \begin{cases} a^{b\%\phi(p)} & \gcd(a,p)=1 \newline a^b & gcd(a,p)\neq 1,b<\phi(p) \newline a^{b\%\phi(p)+\phi(p)} & \gcd(a,p)\neq1,b\geq\phi(p) \end{cases}~(mod~p) \end{split} \]

BSGS

求解

\[y^x\equiv z~(mod~p),~gcd(y,p)==1 \]

解:
\(m=\left \lceil \sqrt p \right \rceil,x=a*m-b,1\leq a\leq m+1,0\leq b<m\)
\(y^{a*m}\equiv z*y^b~(mod~p)\)
把右边值扔进map(unordered_map)里,直接查表即可

namespace bsgs
{
	void solve()
	{
		y%=p,z%=p;
		if(y==0&&z)
		{
			puts("Orz, I cannot find x!");
			return;
		}
		if(z==1)
		{
			puts("0");
			return;
		}
		mp.clear();
		int ans=-0x3f3f3f3f,m=sqrt(p)+1,xx=qpow::qpow(y,m),s=z;
		for(int i=0;i<m;++i)
			mp[s]=i,s=1ll*s*y%p;
		s=1;
		for(int i=1;i<=m+1;++i)
		{
			s=1ll*s*xx%p;
			if(mp.count(s))
			{
				ans=i*m-mp[s];
				break;
			}
		}
		if(ans>0) printf("%d\n",ans);
		else puts("Orz, I cannot find x!");
	}
}

exBSGS

求解

\[y^x\equiv z~(mod~p),~gcd(y,p)\not=1 \]

\(g=gcd(y,p)\)

\[y^{x-1}\equiv \frac{z}{g}*(\frac{y}{g})^{-1}~(mod~\frac{p}{g}) \]

迭代即可。
代码较为毒瘤
下面是\(a^{x}\equiv b~(mod~p)\)

inline int exbsgs(int a,int b,int p)
{
	a%=p,b%=p;
	if(b==1) return 0;
	if(!b&&!a) return 1;
	if(!a) return -1;
	if(!b)
	{
		int ret=0,d=gcd(a,p);
		while(d!=1)
		{
			++ret,p/=d;
			if(p==1) return ret;
			d=gcd(a,p);
		}
		return -1;
	}
	int ret=0,d=gcd(a,p),c=1;
	while(d!=1)
	{
		if(b%d) return -1;
		p/=d,b/=d;
		c=1ll*(a/d)*c%p;
		++ret;
		if(b==c) return ret;
		d=gcd(a,p);
	}
	mp.clear();
	int f=1,m=sqrt(p)+1;
	for(int i=0;i<m;++i)
	{
		mp[1ll*f*b%p]=i;
		f=1ll*f*a%p;
	}
	int tf=f;
	f=1ll*f*c%p;
	for(int i=1;i<=m;++i)
	{
		if(mp.count(f)) return i*m-mp[f]+ret;
		f=1ll*f*tf%p;
	}
	return -1;
}

crt

跳过

excrt

与crt并没有什么关系

\[\begin{split} \begin{cases} a_{1} \equiv b_{1}~mod~p_{1} \newline a_{2} \equiv b_{2}~mod~p_{2} \newline ... \newline a_{n} \equiv b_{n}~mod~p_{n} \newline \end{cases} \end{split} \]

假设我们求出了前\(k-1\)个的一个特解\(x_{0}\),现在求第\(k\)个。
\(M=\prod_{i=1}^{k-1}{p_{i}}\)
则通解为\(x_{0}+k*M\)
\(x_{0}+k*M\equiv b_{k}~~mod~p_{k}\)
\(k*m\equiv b_{k}-x_{0}~~mod~p_{k}\)
exgcd即可

ll lmul(ll x, ll y, ll mod)
{
    ll ans = 0;
    while (y)
    {
        if (y & 1) ans = (ans + x) % mod;
        x = (x + x) % mod;
        y >>= 1;
    }
    return ans;
}
void excrt()
{
    ll ans = b[1], lcm = a[1], tmp, gcd;
    for (int i = 2; i <= k; ++i)
    {
        tmp = ((b[i] - ans) % a[i] + a[i]) % a[i];
        gcd = exgcd(lcm, a[i], x, y);
        x = lmul(x, tmp / gcd, a[i]);
        ans += lcm * x;
        lcm *= a[i] / gcd;
        ans = (ans % lcm + lcm) % lcm;
    }
    printf("%lld\n", ans);
}

lucas

\(C_{n}^{m}\equiv C_{n/p}^{m/p}*C_{n\%p}^{m\%p}~~mod~p\)
p为质数

exlucas

和上一个一样,与lucas并没有什么关系
极为毒瘤
适用于p不为质数的情况
分解p,对于每一个\(p_{i}^k\)分开算,最后用crt合并
example:
对3^2算
\begin{split}
19! &=(1* 2* 4* 5* 7* 8* 10* 11* 13* 14* 16* 17* 19)* (3* 6* 9* 12* 15* 18) \newline
&=(1* 2* 4* 5* 7* 8)^2* 19* 6!* 3^6
\end{split}
按照\(p^k\)分段,每段算再快速幂(第一个括号),剩下的暴力(19),提了因数剩的阶乘递归搞
听上去非常简单

#define ll long long
inline ll inv(ll a,ll p)
{
	ll x,y;
	exgcd(a,p,x,y);
	x=(x%p+p)%p;
	return x;
}
inline ll fac(ll x,ll p,ll pk)
{
	if(!x) return 1;
	ll ans=1;
	for(int i=1;i<=pk;++i)
		if(i%p) ans=1ll*ans*i,ans%=pk;
	ans=qpow(ans,x/pk,pk);
	for(int i=1;i<=x%pk;++i)
		if(i%p) ans=1ll*i*ans,ans%=pk;
	ans=ans*fac(x/p,p,pk)%pk;
	return ans;
}
inline ll c(ll n,ll m,ll p,ll pk)
{
	if(n<m) return 0;
	ll cnt=0;
	for(ll i=n;i;i/=p)
   		cnt+=i/p;
	for(ll i=m;i;i/=p)
		cnt-=i/p;
	for(ll i=n-m;i;i/=p)
		cnt-=i/p;
	return fac(n,p,pk)*inv(fac(m,p,pk),pk)%pk*inv(fac(n-m,p,pk),pk)%pk*qpow(p,cnt,pk)%pk;
}
inline ll crt(ll x,ll p,ll mod)
{
	return inv(p/mod,mod)*(p/mod)*x;
}
inline ll exlucas(ll n,ll m,ll p)
{
	ll t=p,ans=0,k;
	for(int i=2;i*i<=p;++i)
	{
		k=1;
		while(!(t%i)) k=1ll*k*i,t/=i;
		ans+=crt(c(n,m,i,k),p,k),ans%=p;
	}
	if(t>1) ans+=crt(c(n,m,t,t),p,t),ans%=p;
	return ans;
}

二次剩余

\[x^2\equiv a~~mod~p \]

p为奇质数
Cipolla算法
rand一个b使得\((b^2-a)\)为模p下的二次非剩余
\(x=(b+\sqrt{b^2-a})^{\frac{p+1}{2}}\)
需要写一个类似复数运算的东西

#include<bits/stdc++.h>
using namespace std;
#define mc MyComplex
#define pown ((p-1)>>1)
#define ll long long
ll n,p,ra,w,ans1,ans2;
struct MyComplex
{
	ll re,im;
	mc(){}
	mc(ll a,ll b):re(a),im(b){}
	inline friend mc operator * (mc a,mc b)
		{
			return mc((a.re*b.re+a.im*b.im%p*w)%p,(a.re*b.im+a.im*b.re)%p);
		}
};
inline ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1) ans=(ans*a)%p;
		a=(a*a)%p;
		b>>=1;
	}
	return ans;
}
inline mc qpow(mc a,ll b)
{
	mc ans(1,0);
	while(b)
	{
		if(b&1) ans=a*ans;
		a=a*a;
		b>>=1;
	}
	return ans;
}
int main()
{
	srand(time(NULL));
	int t;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%lld%lld",&n,&p);
		n%=p;
		if(n==0)
		{
			puts("0");
			continue;
		}
		if(qpow(n,pown)==p-1)
		{
			puts("Hola!");
			continue;
		}
		while(1)
		{
			ra=rand()%p;
			w=((ra*ra%p-n)%p+p)%p;
			if(qpow(w,pown)==p-1)break;
		}
		mc q(ra,1);
		ans1=qpow(q,pown+1).re,ans2=p-ans1;
		if(ans1==ans2) printf("%lld\n",ans1);
		else printf("%lld %lld\n",min(ans1,ans2),max(ans1,ans2));
	}
	return 0;
}
posted @ 2019-10-04 20:17  123789456ye  阅读(20)  评论(0)    收藏  举报