一、欧几里得算法
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
若gcd (a, b)=m,则gcd (a/m, b/m)=1
最小公倍数 LCM(a,b)=a/gcd(a,b)*b
由题目可知k的范围明显比m大,想到往周期性靠拢
由gcd性质可得gcd(a, b)=gcd(b*t+a, b),题目求的是与m互质的数即gcd(i,m)=1=gcd(m*t+i,m),具有周期性,周期为m,注意k%num==0的情况
#include<cstdio>
using namespace std;
const int n_max=1e6+5;
int f[n_max];
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int main()
{
int m,k;
while(~scanf("%d%d",&m,&k))
{
int num=0;
for(int i=1; i<=m; ++i)
if(gcd(i,m)==1)
f[num++]=i;
printf("%d\n",k%num==0?(k/num-1)*m+f[num-1]:k/num*m+f[k%num-1]);
}
return 0;
}
二、
矩阵快速幂运算
struct matr
{
int m[n_max][n_max];
};
matr x,y;
const int mod=1e9+7;
for(int i=0; i<n; ++i)
y.m[i][i]=1;
matr operator*(matr a,matr b)
{
matr c;
for(int i=0; i<n; ++i)
for(int j=0; j<n; ++j)
{
c.m[i][j]=0;
for(int k=0; k<n; ++k)
c.m[i][j]=(c.m[i][j]+a.[i][k]*b.m[k][j])%mod;
}
}
matr qpow(matr a,matr b,int k)
{
while(k)
{
if(k&1) b=b*a;
a=a*a;
k>>1;
}
return b;
}
qpow(x,y,k);
快速积运算
int qmul(int a,int b)
{
int ans=0;
while(b)
{
if(b&1)
ans+=a;
a<<=1;
b>>=1;
}
return ans;
}
快速幂运算
int qpow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1)
ans*=a;
a*=a;
b>>=1;
}
return ans;
}
快速积取模
int Modmul(int a,int b,int mod)
{
int ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
a<<=1;
a%=mod;
b>>=1;
}
return ans;
}
快速幂取模
int Modpow(int a,int b,int mod)
{
int ans=1;
while(b)
{
if(b&1)
ans=Modmul(ans,a,mod);
a=Modmul(a,a,mod);
b>>=1;
}
return ans;
}
素数筛
bool vis[n_max];
int prime[n_max],cnt;
void sieve()
{
memset(vis,0,sizeof(vis));
int m=sqrt(n_max);
for(int i=2;i<=m;++i)
{
if(!vis[i])
prime[cnt++]=i;
for(int j=i;j<n_max;j+=i)
vis[j]=true;
}
}
三、质因数分解
题目2:ACM-ICPC 2018 南京赛区网络预赛J---Sum
定义f(N)为N的分解组合数
①如果N本身是一个质数,它只能分解为1*N和N*1,f(N)=2
②如果N分解的两个乘数质数p和N/p=x,如果x可以整除p*p,很明显f(N)=0(N无论如何分解,其中一个乘数必定含有p的次方大于等于2);如果x不能整除p,那么对于x的每一个分解,p都可以乘以其中一个乘数而不产生重复,所以f(N)=f(x)*2;如果x仅能整除p,x分解出来的每一个组合必定有其中一个乘数含有p,但f(N)!=f(x),因为此时产生了重复(例如6*3),但可以换一种思维来想,如果再将x的p因子剔除得到y,那么对于y的每一种分解,p都必须同时与两个乘数相乘(将两个p分开),f(N)=f(y)=f(x/p)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cctype>
#include<cmath>
#include<map>
#include<vector>
#include<utility>
#define For(i,x,y) for(int i=x;i<=y;++i)
#define Fov(i,x,y) for(int i=x;i>=y;--i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
#define lowbit(x) x&-x
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=2e7+5;
ll f[n_max];
bool vis[n_max];
int prime[n_max];
int main()
{
int cnt=0;
f[1]=1;
for(int i=2;i<n_max;++i)
{
if(!vis[i])
{
prime[cnt++]=i;
f[i]=2;
}
for(int j=0;j<cnt&&prime[j]*i<n_max;++j)
{
int x=i*prime[j];
vis[x]=true;
if(i%prime[j]==0)
{
if(i%(prime[j]*prime[j])==0)
f[x]=0;
else
f[x]=f[i/prime[j]];
break;
}
else
f[x]=2*f[i];
}
}
for(int i=2;i<n_max;++i)
f[i]+=f[i-1];
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
printf("%lld\n",f[n]);
}
return 0;
}
四、欧拉函数
欧拉函数φ(x):对于整数n,小于n的正整数中与n互质的数的数目
①求单个欧拉函数
int euler(int n)
{
int ans=n;
for(int i=2; i*i<=n; ++i)
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
if(n>1) return ans=ans/n*(n-1);
return ans;
}
②筛法求欧拉函数表
int euler[n_max];
for(int i=2; i<n_max; ++i)
euler[i]=i;
for(int i=2; i<n_max; ++i)
if(euler[i]==i)
for(int j=i; j<n_max; j+=i)
euler[j]=euler[j]/i*(i-1);
五、费马大定理
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cctype>
#include<cmath>
#include<map>
#include<vector>
#define For(i,x,y) for(int i=x;i<=y;++i)
#define Fov(i,x,y) for(int i=x;i>=y;--i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
using namespace std;
typedef long long ll;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
int main()
{
int n,a,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&a);
if(n==0||n>2)
printf("-1 -1\n");
else if(n==1)
printf("%d %d\n",1,a+1);
else
{
if(a&1)
{
int x=(a-1)>>1,b=2*x*x+2*x;
printf("%d %d\n",b,b+1);
}
else
{
int x=a>>1,b=x*x-1;
printf("%d %d\n",b,b+2);
}
}
}
return 0;
}
六、费马小定理
如果p为质数,且a与p互质,则有 ,可推出
取模运算法则
①若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p)和(a * c) ≡ (b * c) (%p);
②若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a - c) ≡ (b - d) (%p),(a * c) ≡ (b * d) (%p),(a / c) ≡ (b / d) (%p);
题目1:HDU6440---Dream
对于任意比质数p小的数a,b, a、b、a+b与p肯定互质,因而根据费马小定理和取模运算法则有 ,因而可以定义a+b为(a+b)%p,a*b为(a*b)%p
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<cctype>
#include<cmath>
#include<map>
#include<vector>
#define For(i,x,y) for(int i=x;i<=y;++i)
#define Fov(i,x,y) for(int i=x;i>=y;--i)
#define midf(a,b) ((a)+(b)>>1)
#define Num1(_) (_)<<1
#define Num2(_) ((_)<<1)|1
using namespace std;
typedef long long ll;
inline int read()
{
char ch=getchar();
int x=0, f=1;
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while('0'<=ch&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int p;
scanf("%d",&p);
For(i,0,p-1)
For(j,0,p-1)
printf("%d%c",(i+j)%p,j==p-1?'\n':' ');
For(i,0,p-1)
For(j,0,p-1)
printf("%d%c",(i*j)%p,j==p-1?'\n':' ');
}
return 0;
}
欧拉定理
若正整数 a , n 互质,则 a^φ(n)≡1(mod n) ;推论:若正整数 a , n 互质,a^p≡a^(p mod φ(n)) (mod n)
题目2:ACM-ICPC 2018 焦作赛区网络预赛G---Give Candies
尝试几个数后得出规律ans=2^(n-1);n的范围极大,题目很明显求的是超高次幂;根据欧拉定理的推论可实现降幂。
#include <bits/stdc++.h>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define L(_) (_)<<1
#define R(_) ((_)<<1)|1
#define fi first
#define se second
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=1e5+10;
const ll mod=1e9+7;
char s[n_max];
int main()
{
//freopen("in.txt","r",stdin);
int T; si(T);
ll mod1=mod-1;
while(T--)
{
ss(s);
int len=strlen(s);
ll n=0,ans=1,x=2;
Fo(i,0,len) n=(n*10+s[i]-'0')%mod1;
--n;
while(n)
{
if(n&1) ans=ans*x%mod;
x=x*x%mod;
n>>=1;
}
printf("%lld\n",ans);
}
return 0;
}
七、莫比乌斯反演
整除分块:求
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}