写这个类型博客的目的就是想总结一下某个专题的知识点,方便以后比赛前复习,由于太菜,如有错误,还请斧正。
首先%运算对于加减乘是没有影响的原先怎么做现在还是怎么做,对于除法呢影响就比较大了,这里我们必须引入一个概念——逆元,逆元其实和倒数差不多,比如a/b对p取模就等于a先对p取模再乘上b基于p的逆元
一般来说求逆元有三种解法
以下参考https://blog.csdn.net/forever_dreams/article/details/82533362
1.费马小定理
int Quick_Power(int a,int b,int c)
{
int ans=1;
while(b)
{
if(b&1)
ans=(1ll*ans*a)%c;
a=(1ll*a*a)%c;
b>>=1;
}
return ans;
}
int main()
{
int a,b,p;
scanf("%d%d%d",&a,&b,&p);
b=Quick_Power(b,p-2,p);
printf("%d",((a%p)*(b%p))%p);
return 0;
}
2.扩展欧几里得定理
void exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int main()
{
int a,b,p,x,y;
scanf("%d%d%d",&a,&b,&p);
exgcd(b,p,x,y);
x=(x+p)%p;
printf("%d",((a%p)*(x%p))%p);
return 0;
}
3.线性筛
int inv[N];
void get_inverse(int n,int p)
{
int i;
inv[1]=1;
for(i=2;i<=n;++i)
inv[i]=(p-p/i)*inv[p%i]%p;
}
int main()
{
int n,i,p;
scanf("%d%d",&n,&p);
get_inverse(n,p);
return 0;
}
当然除了加减乘除这些基本运算以外还有许多地方要用到%
快数幂:
typedef long long ll
ll ppow(ll a, ll b, ll m){
ll ans = 1;
while(b > 0){
if(b & 1){
ans = ans * a % m;
}
a = a * a % m;
b >>= 1;
}
return ans;
}
快数乘
这个比较常用是O(logn)
ll ksc(ll x,ll y,ll p){
ll res=0;
while(y){
if(y&1)res=(res+x)%p;
x=(x<<1)%p; y>>=1;
}return res;
}
这还有O1的(刚刚查到的,没用过)
ll ksc(ll x,ll y,ll p){
ll z=(ld)x/p*y;
ll res=(ull)x*y-(ull)z*p;
return (res+p)%p;
}
最后讲一下负数取模
一般来说负数直接取模会出错(本人接连在这跌倒两次),因此我们只需要将取模操作手动完成就行了
if(a<=-mod)
{
k=a/(-mod);
a+=k*mod;
}