再将这个式子放到\pmod p(modp)意义下就会得到:
k*i+r \equiv 0 \pmod pk∗i+r≡0(modp)
然后乘上i^{-1}i−1,r^{-1}r−1就可以得到:
k*r^{-1}+i^{-1}\equiv 0 \pmod pk∗r−1+i−1≡0(modp)
i^{-1}\equiv -k*r^{-1} \pmod pi−1≡−k∗r−1(modp)
i^{-1}\equiv -\lfloor \frac{p}{i} \rfloor*(p \bmod i)^{-1} \pmod pi−1≡−⌊ip⌋∗(pmodi)−1(modp)
详见这里
//板子
//递推线性时间求乘法逆元
#include
using namespace std;
const int N=20000530;
int n,p,inv[N];
int main()
{
cin>>n>>p;
inv[1]=1;
for(int i=2;i<=n;i++)
{
inv[i]=(long long)(p-p/i)*inv[p%i]%p;
}
for(int i=1;i<=n;i++)cout<
2.费马小定理:a^(p-1) ≡ 1 (mod p)p是质数,可以用来求单次乘法逆元,由费马小定理 a^(p-1)≡1 , 变形得 a * a^(p-2)≡1(mod p);若a,p互质,因为a * a^(p-2)≡1(mod p)且a*x≡1(mod p),则x=a^(p-2) (mod p),用快速幂可快速求之。
3.拓展欧几里得算法,可以对ax+by=c这样的不定方程求解,a,b,c为整数。若要使方程有解,则必须满足gcd(a,b)|c, (即c%gcd(a,b)=0)。 而在题目中一般会让我们求x的最小正整数解,只需要解出其中一组解,x可能非常大或为负数,x=(x%b+b)%b;给x批量加上b,可以保持ax+by=1成立,且满足x为最小正整数解
例题:同余方程
#include
using namespace std;
//设置为全局变量,在递归栈中返回时更改
//还有一种写法,写在函数内,调用地址,大概就这样,int& x
long long x,y;
void exgcd(long long a,long long b)
{
//要求ax+by=gcd(a,b)成立
//可以通过x1,y1推出x0,y0,层层递归
//当b=0时,方程必有解,也是递归的出口
if(b==0)//特殊解
{
x=1;
y=0;
return;
}
exgcd(b,a%b);
long long tx=x;//暂存
x=y;
y=tx-a/b*y;//有证明的,在题解里面QWQ,背一下也蛮香的
}
int main()
{
long long a,b;
cin>>a>>b;
exgcd(a,b);//求出x的一组解
x=(x%b+b)%b;//x可能为负数,或一个很大的值,给x批量加上b,可以找到最小正整数解
cout<
青蛙的约会
#include
using namespace std;
long long c,x,y,m,n,l,g;
void exgcd(long long a,long long b)
{
if(b==0)//递归出口时a必为gcd(a,b)
{
x=1;
y=0;
g=a;//gcd(a,b)
return;
}
exgcd(b,a%b);
long long tx=x;
x=y;
y=tx-a/b*y;
}
int main()
{
scanf("%lld %lld %lld %lld %lld",&x,&y,&m,&n,&l);
//写成ax+by=c的形式
long long a=n-m,b=l;
c=x-y;
if(a<0)a=-a,c=-c;//a,b一定是正的好像因为gcd中的a,b要是正的 。x,y可以是负的
exgcd(a,b);//先求出ax+by=gcd(a,b)的一组解
if(c%g)
{
cout<<"Impossible";
return 0;
}
x=x*c/g;//x为ax+by=c的一组解 c=k*gcd(a,b)
x=(x%(b)+(b))%(b/g);//最小正整数解
//b/g 是最小单元,最后那个必须模b,否则会wa掉两个点
//如 x=(x%(b)+(b))%(b);是不行的
cout<
4.中国剩余定理:例题:猜数字(板子题),(定理的正确性其实很好证的,就是数字有点多),数据有坑点,①bi<=10^18,直接相乘可以爆long long,
,所以必须要用快速乘(简单来说一点点乘),②a[i]可能为负数,要把它转为正,(不确定就转正数吧,毕竟我也搞不太清楚)
#include
#include
#define ll long long
ll a[13],b[13],k,M=1,x,y,ans=0;
using namespace std;
ll ksc(ll x,ll y,ll mod)
{
ll tmp=0;
for(;y;y>>=1,x=x*2%mod)if(y&1)tmp=(tmp+x)%mod;
//b的末尾为1,则对答案有贡献
return tmp;
}
void exgcd(ll a,ll b)
{
if(b==0)
{
x=1;y=0;return;
}
exgcd(b,a%b);
ll tx=x;
x=y;
y=tx-a/b*y;
}
int main()
{
cin>>k;
for(int i=1;i<=k;i++)cin>>a[i];
for(int i=1;i<=k;i++)
{
cin>>b[i];M*=b[i];
}
for(int i=1;i<=k;i++)a[i]=(a[i]%b[i]+b[i])%b[i];
for(int i=1;i<=k;i++)
{
ll mi=M/b[i];
exgcd(mi,b[i]);//前面那个是n-1个数之积,后面那个数,就一个数
ll ti=(x%b[i]+b[i])%b[i];//exgcd求乘法逆元,这里gcd(a,b)=1,所以b不用写成b/gcd(a,b)
ans=(ans+ksc(mi,ksc(a[i],ti,M),M))%M;
}
printf("%lld",ans);
return 0;
}
5.欧拉定理,埃氏筛法,线性筛,区间筛,光速幂。。。以后来填坑
6.几个优秀的题解,讲解1,讲解2,讲解3, 中国剩余定理