Noip前的大抱佛脚----数论

数论

知识点

Exgcd

\(O(logn)\)求解\(Ax+By=C\)的问题
1、若\(C\%gcd(A,B)!=0\)则无解
2、\(Gcd=gcd(A,B);A/=Gcd,B/=Gcd,C/=Gcd\)
3、代入下面代码求\(Ax+By=1\)
4、\(x*C\),得到一组特解
5、通解为\(\begin{cases}x=x_0+k*B \\y=y_0+k*A\end{cases}\)

void Exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b){x=1;y=0;return;}
    Exgcd(b,a%b,y,x);y-=a/b*x;
}

逆元

在\(gcd(A,P)==1\)时,\(A\)在模\(P\)意义下存在逆元(证明可以符合Exgcd有解的证明),其余情况不存在逆元

通常\(P\)为质数时就是\(A^{p-2}\)作为逆元(费马小定理)

  • 欧拉定理(费马小定理) \(x^{-1}\equiv x^{p-2}(mod\ p)\),要求\(p\)为质数
  • 解方程(Exgcd)\(Px+Ay=1,A=\frac{1}{y}(mod\ P)\)
  • 线性递推逆元:

    令\(a=\lfloor\frac{p}{i}\rfloor,b=p\%i\),则有\(ai+b=p,i\equiv-\frac{b}{a}(mod\ p),\frac{1}{i}\equiv-\frac{a}{b}(mod\ p)\)

    由于\(b<i\),所以\(b\)的逆元已经求出,直接可以得到:

    inv[i]=p-(p/i*inv[p%i])%p;

    ?

gcd

具有一些奇妙的性质,如可合并

  • 往数集中加入一个数,要么gcd不变,要么至少变为原来的\(\frac{1}{2}\)(所以可以用来分块了(同样的xor也每次只会增加log次))

欧拉函数\(\varphi(x)\)

表示小于x且与x互质的数的个数

计算公式

\[\varphi(n)=n*\prod(1-\frac{1}{p_i})\],其中\(p_i\)表示\(n\)的不相同的质因子

欧拉公式

\[a^{\varphi(p)}\equiv 1\ (mod \ p)\]

降幂公式

  • \(x,p\)互质:\(x^k\equiv x^{k\%\varphi(p)}\ (mod\ p)\)
  • \(x,p\)不互质:\(x^k\equiv \begin{cases}x^{k}\ (mod\ p),k\le\varphi(p) \\x^{k\%\varphi(p)+\varphi(p)}\ (mod\ p),k>\varphi(p)\end{cases}\)

CRT&EXCRT

\(O(nlogn)\)求解一系列同余方程,如

\[\begin{cases}x\equiv A_1(mod\ P_1) \\x\equiv A_2(mod\ P_2) \\...\\x\equiv A_n(mod\ P_n) \\\end{cases}\]

代码如下(未判无解)

ll gcd(ll a,ll b) {return !b?a:gcd(b,a%b);}
void Exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b) {x=1;y=0;return;}
    Exgcd(b,a%b,y,x);y-=a/b*x;
}
int EXCRT()
{
    for(int i=2;i<=n;i++)
    {
        ll g=gcd(P[i-1],P[i]),C=(A[i]-A[i-1])/g,x,y;
        Exgcd(P[i-1]/g,P[i]/g,x,y);
        P[i]=P[i-1]*P[i]/g;
        A[i]=A[i-1]+P[i-1]*x*C;
        A[i]=(A[i]%P[i]+P[i])%P[i];
    }
    return A[n];
}

方法是每次合并两个方程,手推式子\(P[i]x+A[i]=P[i+1]y+A[i+1]\ \ \ ->\ \ \ P[i]x+P[i+1]y=A[i+1]-A[i]\)

可以发现模数为原来的\(lcm\)(先除以\(gcd\)再乘,很容易爆\(long\ long\)),余数为原来余数加上模数的\(x\)倍

注意经常x算出来是负数所以时刻\(+mod)\%mod !\)

有的时候题目并没有那么裸

  • \(x\)前带系数(屠龙勇士)

\(Ax\equiv B(mod\ p)\ \ ->\ \ Ax+pk=B(当且仅当B\%gcd(A,p)==0时有解)\ \ ->\ \ x=x_0+tp\ \ ->\ \ x\equiv x_0(mod\ p)\)

  • CRT合并答案

对于一些公式,只适用于模数是质数的情况,而题目要求的模数要是任意正数,所以可以求得

\[\begin{cases}Ans\equiv A_1(mod\ P_1) \\Ans\equiv A_2(mod\ P_2) \\...\\Ans\equiv A_n(mod\ P_n) \\\end{cases}\]

然后用CRT合并答案,求得\(Ans\equiv OUTANS\ (mod\ Mod)\)

但是就所见到的题目来说(任意模数NTT),只有在答案不太大的时候适用,例如该题答案不会超过\(10^9*10^9*10^5=10^{23}\),方法是选取三个乘积大于\(10^{23}\)的NTT模数,得到

\[\begin{cases}Ans\equiv A_1(mod\ P_1×P_2) \\Ans\equiv A_2(mod\ P_3) \\\end{cases}\]

令\(M=P_1*P_2\)于是\(Ans=kM+A_1=k_3P_3+A_2\),即\(kM+A_1\equiv A_2(mod\ P_3)\)

由于\(Ans\le10^{23}<P_1P_2P_3=MP_3\),所以\(k<P_3\),根据此同余方程可以求得\(k\)在\(mod\ P_3\)的解也就是\(k\)的实际值

然后就可以带入求得答案\(Ans=kM+A_1\)了,不过会爆\(long\ long\),可以采用这个

ll mul(ll x,ll y,ll p) {return (x*y-(ll)(long double)x/p*y+0.5)*p+p)%p;}

BSGS&EXBSGS

快速(\(O(\sqrt n)\))求解\(A^x=B(mod\ P)\)的\(x\)的解,板子题:[SDOI2013]随机数生成器

普通的BSGS要求P是质数,拓展的可以不用是质数

通过降幂公式,能够知道\(x\le P-1\),令\(M=\sqrt P\),则\(x=iM+j\),可以枚举\(i\)的值,得到\(t=A^{(i+1)M}\),查表看是否存在\(T=A^{M-j}B\)满足条件,得到解就返回,这样就能保证解是最小的了

int BSGS(int A,int B,int P)
{
    if(!A%P) return -1;
    int M=sqrt(P)+1;Hash.reset();
    for(int i=0,t=B;i<M;i++,t=1ll*t*A%P) Hash.Add(t%Mo,t,i);//存入B*A^i的哈希值
    for(int i=1,bs=ksm(A,M,P),t=bs;i<=M;i++,t=1ll*t*bs%P)//t=A^{(i+1)M}
        if(Hash.Query(t)!=-1) return i*M-Hash.Query(t);
    return -1;
}

FFT/NTT/MTT/FWT

板子

原根相关

定义:

原根类似于FFT的单位复根,使得能够进行取模操作

NTT模数是指有原根且是\(r×2^k+1\)的形式的模数,如\(998244353(3)\)、\(1004535809(3)\)

存在性及判定

一个数有原根当且仅当它为\(2,4,p,2p,p^r\)(p为奇质数)

\(g^1,g^2...g^{\phi(p)}\)在\(mod\ p\)下各不相同,且\(g^{\phi (p)}=1\),当p为质数时,也就是说\(g^1...g^{p-1}\)分别对应\(1...p-1\)

在\(p\)为质数时,令\(p-1=p_1^{a1}p_2^{a_2}...p_n^{a_n}\),若存在\(g^{\frac{p-1}{p_i}}=1\)则\(g\)不是原根,否则是原根(证明

注意点

  • 两个多项式最高次项分别为\(l1,l2\),那么需要开的长度(包括0)是\(>l1+l2\)的第一个形如\(2^k\)的数

组合公式

  • 从\((0,0)\)走到\((n,m)\),不碰到直线\(y=x+b\)的方案数:\(C(n+m,n)-C(n+m,n-b)\)

    意义为沿着直线翻折,越过直线的路径对称域从翻着顶点到终点的路径

斯特林数

第一类斯特林数

第一类斯特林数:\(n\)个人坐\(m\)张圆桌的方案数(人不同,圆桌相同,n个元素构成m个圆排列)

\[s[n,m]=s[n-1,m-1]+s[n-1,m]*(n-1)\]

第二类斯特林数

第二类斯特林数:\(n\)个球放入\(m\)个盒子的方案数(球不同,盒子相同,n个元素分成m个非空集合)

\[S\{n,m\}=S\{n-1,m-1\}+S\{n-1,m\}*m\]

常用数学公式

  • 平方和的前缀和 \(\sum_{i=1}^{n}i^2=\frac{n(n+1)(2n+1)}{6}\)
  • 立方和的前缀和 \(\sum_{i=1}^{n}i^3=(\frac{n(n+1)}{2})^2\)

位运算

子集枚举

\(0\)~\(2^n\)的子集个数之和是\(3^n\)(一个位置可以有三种情况:没被选到、选到但是没有被子集枚举到、选到并被枚举到)

以下可以快速求子集

for(int i=s;;i=(i-1)&s)
{
    //do whatever you want
    if(!i) break;
}

高维前缀和

统计子集

for(int p=0;p<=20;p++)
    for(int i=0;i<1<<p;i++)
        if(i&(1<<p)) f[i]+=f[i^(1<<p)];

统计超集

for(int p=0;p<=20;p++)
    for(int i=0;i<1<<p;i++)
        if(!(i&(1<<p))) f[i]+=f[i|(1<<p)];

技巧经验

容斥

  • 从\((0,0)\)到\((n,m)\)且不经过一些禁点的方案数(BZOJ两双手)

    \(f[i]=\sum_{j=0}^{j<i}-f[j]*way(j,i),f[0]=-1,way(j,i)\)表示从j点到i点的方案数,按照从\((0,0)\)走到该点的所需步数排序

组合计数

  • 可以画成二维平面上的点去移动,辅助理解、推式子

有趣的式子

gcd有关

  • \(\sum_{i=1}^{n}gcd(i,n)\)

    \(=\sum_{d=1}^{n}(d\sum_{i=1}^{n}[gcd(i,n)==d])\)

    \(=\sum_{d=1}^{n}d\varphi(\frac{n}{d})\)(当然到这步就可以\(O(n\sqrt n)\)做了)

    \(=\sum_{d=1}^{n}\frac{n}{d}\varphi(d)\)

    \(=\sum_{d=1}^{n}\frac{n}{d}d\prod_{p_i|d}\frac{p_i-1}{p_i}\)

    \(=n\sum_{d=1}^{n}\prod_{p_i|d}\frac{p_i-1}{p_i}\)

    考虑每个质数选或者不选的生成函数:\((b_i\frac{p_i-1}{p_i}+1)\),其中\(b_i\)表示\(p_i\)的指数,含义为选了这个质数就会有\(b_i\)种指数

    所以最后答案就是\(n\prod_{p_i|n}(b_i\frac{p_i-1}{p_i}+1)\)

    ?

原文地址:https://www.cnblogs.com/xzyxzy/p/9903896.html

时间: 2024-11-01 11:02:20

Noip前的大抱佛脚----数论的相关文章

Noip前的大抱佛脚----文章索引

Noip前的大抱佛脚----赛前任务 Noip前的大抱佛脚----考场配置 Noip前的大抱佛脚----数论 Noip前的大抱佛脚----图论 Noip前的大抱佛脚----动态规划 Noip前的大抱佛脚----数据结构 Noip前的大抱佛脚----根号对数算法 Noip前的大抱佛脚----字符串 Noip前的大抱佛脚----一些思路 Noip前的大抱佛脚----奇技淫巧 原文地址:https://www.cnblogs.com/xzyxzy/p/9903933.html

Noip前的大抱佛脚----一些思路

一些有启发性的思路 序列 线段树(当然还要有主席树啊!) 差分和前缀和啊 分块 莫队 看到等差数列先推一波式子啊(天天爱跑步) 有序序列的动态插入删除 有的时候需要算贡献,当你发现序列(离散化后)值域一定时,便可以尝试使用树状数组 维护\(mex\) 可以尝试使用值域分块,当这个块内全部有值了就打个\(tag\) 等和序列 大概就是说可以多项式乘起来那种吧,可以发现差分之后是回文串! 序列差分 异或序列可以差分!!(具体差分方法:遇到一个1,给当前位置和下一个位置异或上一个1,这样统计前缀和后就

Noip前的大抱佛脚----根号对数算法

根号算法 分块 数列分块入门九题(hzwer) 入门题1,2,3,4,5,7 问题:给一段区间打上标记后单点查询 解法:主要是每块维护一些标记,计算答案等,此类分块较为简单 注意:块大小一般为\(\sqrt n\) 复杂度:\(O(n\sqrt n)\) 入门题6 问题:每次朝数列中间插入一个元素,查询第k个元素是什么 解法:块大小超过一定值后暴力重构!采用链表实现 复杂度:\(O(n\sqrt n)\) 入门题8 问题:每次询问一个区间内为\(c?\)的元素个数,并把整个区间改为\(c?\)

Noip前的大抱佛脚----数据结构

数据结构 线段树 注意:空间开4倍 神奇标记 From8.26 Test_zsy(CPU监控) 如果一个点权为\(val\)的点被打上了\((a,b)\)标记,那么他的实际点权为\(max(a+val,b)\) 干啥滴? 标记不下放 区间加标记不下放,维护区间max或者最大值 方法是当前\(tag\)维护当前区域标记,\(t\)维护左右儿子的\(max+tag[now]\),并没有快多少,如果仍然忘记见提交记录 并查集 维护二分图 并查集每个点维护是否要改颜色,然后按秩合并/按大小合并即可 实际

NOIP前必须记住的30句话

NOIP前必须记住的30句话 1.比赛前一天晚上请准备好你的各种证件,事先查好去往考场的路线2.比赛之前请先调整你的屏幕分辨率到你喜欢的大小3.比赛之前请把编译器的字体调为你平时惯用的字体,尤其是注意这种字体中的逗号,点,1,l这种易混淆的字是不是区分明显4.在不影响视野的情况下,请将字号尽可能调大,方便查错5.请将题目通读完以后,再开始深入思考你认为最容易的一道题6.即使这道题再容易,也不要着急写代码,请先明确自己每一步要干什么后,再开始写,轻敌会是你最大的错误7.即使这道题看起来再没法做,也

从一个序列中获取前K大的数的一种方法

这个方法是利用快速排序的.在快速排序中,得到中间元素(pivot)之后,比较中间元素之前的元素个数和K的大小关系,从而确定后面该往哪个方向继续递归.如果中间元素前面的元素个数等于K,那就停止递归过程:如果中间元素前面元素个数小于K,那就再中间元素后面进行递归:否则就往中间元素前面进行递归.这样最终得到的是没有排序的前K大的元素,这样再对前K个元素进行一次真正的快速排序.这样就能得到排好序的前K大元素.我随机生成了一个100000个整型数据的文件进行测试,求前10000个元素.这样做用了0.984

hdu 1280 前m大的数 哈希

前m大的数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10574    Accepted Submission(s): 3686 Problem Description 还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小

【hdu1280】前M大的数

前m大的数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 19208    Accepted Submission(s): 6563 Problem Description 还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希

统计前k大的数x

我终于敲上了题目--记起来啦! 描述 给定一个数组,统计前k大的数并且把这k个数从大到小输出. 输入 第一行包含一个整数n,表示数组的大小.n < 100000. 第二行包含n个整数,表示数组的元素,整数之间以一个空格分开.每个整数的绝对值不超过100000000. 第三行包含一个整数k.k < n. 输出 从大到小输出前k大的数,每个数一行. 样例输入 10 4 5 6 9 8 7 1 2 3 0 5 样例输出 9 8 7 6 5 //AC自动机x #include<iostream&