xgzc的数论总结
attention
证略
9.14 Day 1
狄利克雷卷积
满足交换律,数乘结合律,函数结合律,数乘分配律,函数分配律,单位元\(\epsilon(n)=[n==1]\)
莫比乌斯反演
\(f=g×1\)
其中
线性筛
众所周知,线性筛可以筛所有积性函数。
设\(f\)为积性函数。
1.求出\(f(1),f(p)\),p 为质数。
2.求出\(f(p^k)\)与\(f(p^{k-1})\)的关系。
一个例子
求\(f=id^2*\mu\),其中乘号为狄利克雷卷积。
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})}\)也就是狄利克雷卷积
魔力筛
考虑你有一个非积性函数 f 。
现在按上面的,你要求\(f×\mu\)(狄利克雷卷积)。
显然你不能线性筛。
一般的暴力是\(O(n\sqrt n)\)的,优化一下能做到\(O(n\log n)\)
然而这个筛是\(O(n\log\log n)\)的
设
状态转移为
\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
扩展欧拉定理
BSGS
求解
解:
设\(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
求解
设\(g=gcd(y,p)\)
迭代即可。
代码较为毒瘤
下面是\(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并没有什么关系
假设我们求出了前\(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;
}
二次剩余
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;
}
There is a negligible beginning in all great action and thought.

浙公网安备 33010602011771号