\数论四大定理(百度百科):
威尔逊定理
编辑
概念
p可整除(p-1)!+1是p为质数的充要条件
证明
充分性
如果p不是素数,
当p=4时,显然(p-1)!≡6≡2(mod p),
当p>4时,若p不是完全平方数,则存在两个不等的因数a,b使得ab=p,
则(p-1)!≡nab≡0(mod p);
若p是完全平方数即p=k^2,因为p>4,所以k>2,k,2k<p,
(p-1)!≡n(k*2k)≡n'k^2≡0(mod p)。
必要性
若p是素数,取集合 A={1,2,3,...p -1}; 则A 构成模p乘法的缩系,即任意i∈A ,存在j∈A,使得:( i j ) ≡ 1 ( mod p )
那么A中的元素是不是恰好两两配对呢?
不一定,但只需考虑这种情况x^2 ≡ 1 ( mod p )
解得: x ≡ 1 ( mod p ) 或 x ≡ p - 1 ( mod p )
其余两两配对;故而( p - 1 )! ≡ 1﹡( p -1 ) ≡ -1 ( mod p )
欧拉定理
编辑
概念
欧拉定理,也称费马-欧拉定理。
若n,a为正整数,且n,a互素,即gcd(a,n) = 1,则
a^φ(n) ≡ 1 (mod n)
证明
设x(1),x(2),...,x(φ(n))是一个以n为模的缩系,
则ax(1),ax(2),...,ax(φ(n) )也是一个以n为模的缩系(因为(a,n)=1)。
于是有ax(1)ax(2)...ax(φ(n) )≡x(1)x(2)...x(φ(n))(mod n),
所以a^φ(n) ≡ 1 (mod n)。证毕。
孙子定理
编辑
概念
孙子定理,又称中国剩余定理。
中国剩余定理说明:假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,方程组S有解,并可构造得出。构造详见词条“中国剩余定理”。
证明
将构造结果代入验证即可。
费马小定理
编辑
概念
假如p是质数,若p不能整除a,则 a^(p-1) ≡1(mod p),若p能整除a,则a^(p-1) ≡0(mod p)。
若p是质数,且a,p互质,那么 a的(p-1)次方除以p的余数恒等于1。
证明
因为p是质数,且(a,p)=1,所以φ(p)=p-1。
由欧拉定理可得a^(p-1) ≡1(mod p)。证毕。
对于该式又有a^p ≡a(mod p),而且此式不需要(a,p)=1,
所以,费马小定理的另一种表述为:假如p是质数,a是整数,那么a^p ≡a(mod p)。
MillerRabin判素
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll kuaisumi(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans=(ans*a)%mod;
}
a=(a*a)%mod;
b>>=1;
}
return ans;
}
int pansu(ll x,ll n)
{
// 判断n是否为质数;
ll y=n-1;
while(!(y&1)) y>>=1;
x=kuaisumi(x,y,n);
while(y<n-1&&x!=1&&x!=n-1)
{
x=(x*x)%n;
y<<=1;
}
return x==n-1||y&1==1;
}
int isprime(ll n)
{
if(n==2||n==7||n==61) return 1;
if(n==1||(n&1)==0) return 0;
return pansu(2,n)&&pansu(7,n)&&pansu(61,n);
}
int main()
{
ll x=170;
//printf("qwd");
printf("%d\n",isprime(x));
return 0;
}
A - Prime Distance (素数区间筛)求l-R区间里的素数(r-l)<1e6https://vjudge.net/contest/340968#problem/A
大体思路就是欧拉筛得最大根号下的素数,然后区间埃式筛出所有和数,把数组下标漂移L位。
The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number theoreticians for thousands of years is the question of primality. A prime number is a number that is has no proper factors (it is only evenly divisible by 1 and itself). The first prime numbers are 2,3,5,7 but they quickly become less frequent. One of the interesting questions is how dense they are in various ranges. Adjacent primes are two numbers that are both primes, but there are no other prime numbers between the adjacent primes. For example, 2,3 are the only adjacent primes that are also adjacent numbers.
Your program is given 2 numbers: L and U (1<=L< U<=2,147,483,647), and you are to find the two adjacent primes C1 and C2 (L<=C1< C2<=U) that are closest (i.e. C2-C1 is the minimum). If there are other pairs that are the same distance apart, use the first pair. You are also to find the two adjacent primes D1 and D2 (L<=D1< D2<=U) where D1 and D2 are as distant from each other as possible (again choosing the first pair if there is a tie).
Input
Each line of input will contain two positive integers, L and U, with L < U. The difference between L and U will not exceed 1,000,000.
Output
For each L and U, the output will either be the statement that there are no adjacent primes (because there are less than two primes between the two given numbers) or a line giving the two pairs of adjacent primes.
Sample Input
2 17
14 17
Sample Output
2,3 are closest, 7,11 are most distant.
There are no adjacent primes.
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxx=1e6+100;
#define ll long long
const ll mod=1e9+7;
ll sushu[maxx],biaoji[maxx]={0};
ll cnt=0;
ll dabiao[maxx];
ll sushu2[maxx];
void sushushai()
{
for(int i=2;i<maxx;i++)
{
if(!biaoji[i]) sushu[++cnt]=i;
for(int j=1;j<=cnt&&i*sushu[j]<maxx;j++)
{
biaoji[i*sushu[j]]=1;
if(i%sushu[j]==0) break;
}
}
}
ll p=0;
void qujianshai(ll l,ll r)
{
p=0;
memset(dabiao,0,sizeof(dabiao));
for(int i=1;i<=cnt&&sushu[i]*sushu[i]<=r;i++)
{
ll x=l/sushu[i]+(l%sushu[i]>0);
if(x==1) x=2;
for(int j=x;j*sushu[i]<=r;j++)
{
if(j*sushu[i]>=l)
dabiao[j*sushu[i]-l]=1;
}
}
for(int i=0;i<=r-l;i++)
{
if(dabiao[i]==0)
{
if((i+l)!=1)
sushu2[++p]=i+l;
}
}
}
int main()
{
sushushai();
//for(int i=1;i<10;i++) printf("%lld\n",sushu[i]);
ll l,r,n,m;
while(~scanf("%lld%lld",&l,&r))
{
qujianshai(l,r);
//for(int i=1;i<=p;i++)
//printf(" %lld",sushu2[i]);
if(p<2)
{
printf("There are no adjacent primes.\n");
}
else
{
ll juli=20*mod;
ll x,y,a,b;
ll minl=0;
for(int i=1;i<p;i++)
{
if(sushu2[i+1]-sushu2[i]<juli)
{
juli=sushu2[i+1]-sushu2[i];
x=sushu2[i];y=sushu2[i+1];
}
if(sushu2[i+1]-sushu2[i]>minl)
{
minl=sushu2[i+1]-sushu2[i];
a=sushu2[i];b=sushu2[i+1];
}
}
printf("%lld,%lld are closest, %lld,%lld are most distant.\n",x,y,a,b);
}
}
return 0;
}
Eddy's爱好(容斥原理)
Ignatius 喜欢收集蝴蝶标本和邮票,但是Eddy的爱好很特别,他对数字比较感兴趣,他曾经一度沉迷于素数,而现在他对于一些新的特殊数比较有兴趣。
这些特殊数是这样的:这些数都能表示成M^K,M和K是正整数且K>1。
正当他再度沉迷的时候,他发现不知道什么时候才能知道这样的数字的数量,因此他又求助于你这位聪明的程序员,请你帮他用程序解决这个问题。
为了简化,问题是这样的:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。
Input
本题有多组测试数据,每组包含一个整数N,1<=N<=1000000000000000000(10^18).
Output
对于每组输入,请输出在在1到N之间形式如M^K的数的总数。
每组输出占一行。
Sample Input
10
36
1000000000000000000
Sample Output
4
9
1001003332
搞了半天终于明白了:首先,从1到n符合条件的数都为次方数,但是肯定为超时,然后考虑次方数最大也就是60,然后把2到60次方的情况全加上,但是考虑到4的4次方就是16的二次方,这就重复了,所以当次方数为素数的时候这种情况可以避免,4,9,16,25,36,49,64,81...(2次方的结果)8,27,64...(3次方的结果),可以发现64被选择了两次,也就是2的6(2*3)次方,就是两个集合容斥的结果。但是还有一种情况,如2的(2*3*5)次方被pow(pow(2,15),2) pow(pow(2,6),5) pow(pow(2,10),3)筛了三次,但是这三次都被第二种删掉了,所以需要加上,且最多只有三集合的情况,因为2*3*5*7>60;
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#pragma GCC optimize(2)
const int maxx=1e6+19;
#define ll long long
ll a[maxx],biaoji[200]={0},cnt=0,sushu[200];
void sushushai()
{
for(int i=2;i<100;i++)
{
if(!biaoji[i])
sushu[++cnt]=i;
for(int j=i*2;j<100;j+=i)
{
biaoji[j]=1;
}
}
}
ll n;
ll f(ll x)
{
// n中有多少个x次方数。
return pow(n,1.0/x)-1;
}
int main()
{
ll i,j,p,t,k;
sushushai();
// for(i=1;i<19;i++) printf("%lld\n",sushu[i]);
while(cin>>n)
{
ll ans=0;
for(i=1;i<18;i++)
{
ans+=f(sushu[i]);
}
for(i=1;i<18;i++)
for(j=i+1;j<18;j++)
{
ans-=f(sushu[i]*sushu[j]);
}
for(i=1;i<18;i++)
for(j=i+1;j<18;j++)
for(k=j+1;k<18;k++)
{
ans+=f(sushu[i]*sushu[j]*sushu[k]);
}
printf("%lld\n",ans+1);
}
return 0;
}
口算训练(二分+素数筛+唯一分解定理)
小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为nn的正整数序列a1,a2,...,ana1,a2,...,an,要求小T抛出mm个问题以训练他的口算能力。
每个问题给出三个正整数l,r,dl,r,d,小Q需要通过口算快速判断al×al+1×...×ar−1×aral×al+1×...×ar−1×ar是不是dd的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
Input
第一行包含一个正整数T(1≤T≤10)T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含两个正整数n,m(1≤n,m≤100000)n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含nn个正整数a1,a2,...,an(1≤ai≤100000)a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来mm行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000)l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。
Output
对于每个问题输出一行,若是倍数,输出Yes,否则输出No。
Sample Input
1
5 4
6 4 7 2 5
1 2 24
1 3 18
2 5 17
3 5 35
Sample Output
Yes
No
No
Yes
每次输入l,r,d;询问l到r中乘积是否为d的倍数。把每一个数挨着唯一分解到二维vector中,存的是挨着的下标,这样不会爆爆内存也不容易查找,毕竟stl里的函数还是好用,然后对于一次查询,将d唯一分解后挨着判断d的因子数在l到r中有多少个就可以了,我的代码不加读入挂会卡T。。。 其实用java大数就好写多了啊,直接前缀乘积就可以了。O1判断
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxx=1e5+12;
vector <int> v[maxx];
int sushu[maxx],biaoji[maxx],cnt=0;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
void sushushai()
{
for(int i=2;i<maxx;i++)
{
if(!biaoji[i]) sushu[++cnt]=i;
for(int j=1;j<=cnt&&sushu[j]*i<maxx;j++)
{
biaoji[sushu[j]*i]=1;
if(i%sushu[j]==0) break;
}
}
}
ll weiyifenjie(ll n,ll xiabiao)
{
for(int i=1;i<=cnt&&sushu[i]*sushu[i]<=n;i++)
{
while(n%sushu[i]==0)
{
v[sushu[i]].push_back(xiabiao);
n/=sushu[i];
}
}
if(n>1)
{
v[n].push_back(xiabiao);
}
}
int judge(ll l,ll r,ll d)
{
for(int i=1;i<=cnt&&sushu[i]*sushu[i]<=d;i++)
{
ll t=0;
while(d%sushu[i]==0)
{
t++;
d/=sushu[i];
}
if(t>0&&upper_bound(v[sushu[i]].begin(), v[sushu[i]].end(), r)- lower_bound(v[sushu[i]].begin(), v[sushu[i]].end(), l)<t)
return 0;
}
if(d>1)
{
if(upper_bound(v[d].begin(), v[d].end(), r)- lower_bound(v[d].begin(),v[d].end(),l)==0)
return 0;
}
return 1;
}
int main()
{
sushushai();
int t,n,m;
t=read();
while(t--)
{
for(int i=0;i<maxx;i++) v[i].clear();
int d;
n=read();m=read();
for(int i=1;i<=n;i++)
{
int x;
x=read();
weiyifenjie(x,i);
}
for(int i=1;i<=m;i++)
{
int l,r;
l=read();r=read();d=read();
if(judge(l,r,d)==1 )printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
2^x mod n = 1(欧拉定理)对于任意互素的a,p有a的欧拉p次方同余1%p,别忘了特判1;
Give a number n, find the minimum x(x>0) that satisfies 2^x mod n = 1.
Input
One positive integer on each line, the value of n.
Output
If the minimum x exists, print a line with 2^x mod n = 1.
Print 2^? mod n = 1 otherwise.
You should replace x and n with specific numbers.
Sample Input
2
5
Sample Output
2^? mod 2 = 1
2^4 mod 5 = 1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx=1e6+16;
ll sushu[maxx],cnt=0,oula[maxx],biaoji[maxx],mod;
inline ll read()
{
ll x=0;
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
void oulashai()
{
for(int i=2;i<maxx;i++)
{
if(!biaoji[i])
{
sushu[++cnt]=i;
oula[i]=i-1;
}
for(int j=1;j<=cnt&&sushu[j]*i<maxx;j++)
{
biaoji[i*sushu[j]]=1;
if(i%sushu[j]!=0)
{
oula[i*sushu[j]]=oula[i]*(sushu[j]-1);
}
else
{
oula[sushu[j]*i]=oula[i]*sushu[j];
break;
}
}
}
}
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans=(ans*a)%mod;
}
a=(a*a)%mod;
b>>=1;
}
return ans;
}
int main()
{
oulashai();
oula[1]=0;
// for(int i=0;i<10;i++) printf("%lld\n",oula[i]);
while(~scanf("%lld",&mod))
{
if(mod%2==0||mod==1)
{
printf("2^? mod %lld = 1\n",mod);
}
else
{
for(int i=1;i<=oula[mod];i++)
{
if(qpow(2,i)%mod==1)
{
printf("2^%d mod %lld = 1\n",i,mod);
break;
}
}
}
}
return 0;
}
Prime Test (大数质因子分解c++)基于米勒罗宾判素,特别好用
Given a big integer number, you are required to find out whether it's a prime number.
Input
The first line contains the number of test cases T (1 <= T <= 20 ), then the following T lines each contains an integer number N (2 <= N < 2 54).
Output
For each test case, if N is a prime number, output a line containing the word "Prime", otherwise, output a line containing the smallest prime factor of N.
Sample Input
2
5
10
Sample Output
Prime
2
#include<iostream>
#include<ctime>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
map<ll, int>m;
const int mod = 1e9+7;
const int times =50;//测试50次
ll mul(ll a, ll b, ll m)
//求a*b%m
{
ll ans = 0;
a %= m;
while(b)
{
if(b & 1)ans = (ans + a) % m;
b /= 2;
a = (a + a) % m;
}
return ans;
}
ll pow(ll a, ll b, ll m)
//a^b % m
{
ll ans = 1;
a %= m;
while(b)
{
if(b & 1)ans = mul(a, ans, m);
b /= 2;
a = mul(a, a, m);
}
ans %= m;
return ans;
}
bool Miller_Rabin(ll n, int repeat)//n是测试的大数,repeat是测试重复次数
{
if(n == 2 || n == 3)return true;//特判
if(n % 2 == 0 || n == 1)return false;//偶数和1
//将n-1分解成2^s*d
ll d = n - 1;
int s = 0;
while(!(d & 1)) ++s, d >>= 1;
//srand((unsigned)time(NULL));在最开始调用即可
for(int i = 0; i < repeat; i++)//重复repeat次
{
ll a = rand() % (n - 3) + 2;//取一个随机数,[2,n-1)
ll x = pow(a, d, n);
ll y = 0;
for(int j = 0; j < s; j++)
{
y = mul(x, x, n);
if(y == 1 && x != 1 && x != (n - 1))return false;
x = y;
}
if(y != 1)return false;//费马小定理
}
return true;
}
ll gcd(ll a, ll b)
{
return b == 0 ? a : gcd(b, a % b);
}
ll pollard_rho(ll n, ll c)//找到n的一个因子
{
ll x = rand() % (n - 2) + 1;
ll y = x, i = 1, k = 2;
while(1)
{
i++;
x = (mul(x, x, n) + c) + n;//不断调整x2
ll d = gcd(y - x, n);
if(1 < d && d < n)
return d;//找到因子
if(y == x)
return n;//找到循环,返回n,重新来
if(i == k)//一个优化
{
y = x;
k <<= 1;
}
}
}
void Find(ll n, ll c)
{
if(n == 1)return;//递归出口
if(Miller_Rabin(n, times))//如果是素数,就加入
{
m[n]++;
return;
}
ll p = n;
while(p >= n)
p = pollard_rho(p, c--);//不断找因子,知道找到为止,返回n说明没找到
Find(p, c);
Find(n / p, c);
}
int main()
{
ll n;srand((unsigned)time(NULL));
ll x;
ll t,y;
cin>>t;
while(t--)
{
cin>>n;
x=0;
m.clear();
ll count =0;
Find(n, rand() % (n - 1) + 1);//这是自己设置的一个数
//cout<<n<<" = ";
for(map<ll ,int>::iterator it = m.begin(); it != m.end();)
{
count++;
if(count==1)
{
x=it->first;
y=it->second;
}
//cout<<it->first<<" ^ "<<it->second;
++it;
//if((++it) != m.end())
// cout<<" * ";
}
if(count==1)
{
if(y==1)
printf("Prime\n");
else
{
printf("%lld\n",x);
}
}
else
{
printf("%lld\n",x);
}
}
return 0;
}
BSGS模板求最小a的b次方取余p==0(复杂度sqrt(p))
超时的map版本:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <map>
#include <ctime>
#define ll long long
using namespace std;
map<int,int>mp;
ll mod,n,a;
ll kuaisumi(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans*=a;
if(ans>mod) ans%=mod;
}
a=a*a;
if(a>mod) a%=mod;
b>>=1;
}
return ans;
}
int main()
{
while(~scanf("%lld%lld%lld",&mod,&a,&n))
{
mp.clear();
int p= (int)sqrt(mod) + 1;
for(ll i=0;i<=p;i++)
{
ll x=n*kuaisumi(a,i);
if(x>mod) x%=mod;
mp[x]=i;
}
int flag=0;
for(ll i=0;i<=p;i++)
{
ll x=kuaisumi(a,i*p);
if(mp[x])
{
if(i*p>=mp[x])
{
printf("%lld\n",i*p-mp[x]);
flag=1;
break;
}
}
if(flag==1) break;
}
if(flag==0) printf("no solution\n");
}
return 0;
}
先进的模板:
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=76543;
ll P,B,N,ans,top,hs[mod],id[mod],Last[mod],Next[mod];
void Insert(ll x,ll y)
{
ll z=x%mod;
hs[++top]=x,id[top]=y,Next[top]=Last[z],Last[z]=top;
}
ll Find(ll x)
{
ll z=x%mod;
for(ll i=Last[z];i;i=Next[i])
if(hs[i]==x) return id[i];
return -1;
}
ll BSGS(ll a,ll b,ll c)
{
if(b==1) return 0;
ll m=ceil(sqrt(c)),j=1,t=1,k;
for(ll i=0;i<m;i++,j=j*a%c) Insert(j*b%c,i);
for(ll i=m;i<=c;i+=m)
if(~(k=Find(t=t*j%c))) return i-k;
return -1;
}
int main()
{
while(~scanf("%lld%lld%lld",&P,&B,&N))
{
top=0,memset(Last,0,sizeof(Last));
ans=BSGS(B,N,P);
if(~ans) printf("%lld\n",ans);
else puts("no solution");
}
return 0;
}
求解a的b次方的所有因子和(唯一分解), 因为在求等比数列的和的时候会出现分子与mod gcd!=1的情况,此时ans为(pow(a,b)-1)/(a-1),a=k*p-1; ans=(k*p-1)^b-1/k*p %p ans=b;就是k*p单个系数之和。自己可以写一下看看
if((yinzi[i]-1)%mod==0)
{
ans=(b*cishu[i]+1)*ans%mod; continue;
}
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod=9901;
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
ll yinzi[600],cishu[600];
ll hanshu(ll a,ll i)
{
ll b=cishu[i];
ll ans=(qpow(a,b)+mod-1);
ans*=qpow(a-1,mod-2);
ans%=mod;
return ans;
}
int main()
{
ll m,k,y,j,t,p,i;
ll a,b;
cin>>a>>b;
if(a==0)
{
if(b==0)
printf("1\n");
return 0;
}
if(a==1)
{
printf("1\n");
return 0;
}
int cnt=0;
for(i=2;i*i<=a;i++)
{
if(a%i==0) yinzi[++cnt]=i;
while(a%i==0)
{
cishu[cnt]++;
a/=i;
}
}
if(a>1)
{
yinzi[++cnt]=a;
cishu[cnt]++;
}
ll ans=1;
for(i=1;i<=cnt;i++)
{
if((yinzi[i]-1)%mod==0)
{
ans=(b*cishu[i]+1)*ans%mod; continue;
}
cishu[i]*=b;
cishu[i]++;
//printf("%lld %lld %lld\n",yinzi[i],cishu[i],hanshu(yinzi[i],i));
ans=(ans*hanshu(yinzi[i],i))%mod;
}
printf("%lld\n",ans);
return 0;
}
后续继续,加油!