数论总结
来源:互联网 发布:mac可以接鼠标吗 编辑:程序博客网 时间:2024/06/10 20:24
- 数论总结
- 欧拉定理
- 求欧拉函数
- 素数筛
- Miller_Rabin 算法进行素数测试 pollard_rho 算法进行质因数分解
- 求1n的素数的个数1e11
- 计算二次剩余
- 计算离散对数
- 原根
- 组合数学
- 第一类斯特林数
- 第二类斯特林数
- Lucas定理
- 欧拉定理
数论总结
欧拉定理
使用条件为gcd(a,n) = 1。
欧拉降幂公式:
求欧拉函数:
//直接求phi int get_phi(int c) { LL ans = c; int m = sqrt(c+0.5); for(int i = 2; i <= m; ++i) { if(c % i == 0) { ans = ans/i*(i-1); while(c % i ==0)c/=i; } } if(c > 1)ans = ans/c*(c-1); return ans; }
//线性筛法,快的飞起 bool vis[MAXN]; int prime[MAXN]; int phi[MAXN]; int tot; void init() { memset(vis, false, sizeof(vis)); phi[1] = 1; tot = 0; for(int i = 2; i < MAXN; i ++) { if(!vis[i]) { prime[tot ++] = i; phi[i] = i - 1; } for(int j = 0; j < tot; j ++) { if(i * prime[j] >= MAXN) break; vis[i * prime[j]] = 1; if(i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; } else { phi[i * prime[j]] = phi[i] * phi[prime[j]]; } } } }
素数筛:
void get_prim() { for(int i = 2; i < MAXN; ++i) { if(!vis[i])prim[tot++] = i; for(int j = 0; j < tot; ++j) { if(prim[j]*i > MAXN)break; vis[i*prim[j]] = 1; if(i%prim[j] == 0)break; } } }
Miller_Rabin 算法进行素数测试 pollard_rho 算法进行质因数分解
//**************************************************************** // Miller_Rabin 算法进行素数测试 //速度快,而且可以判断 <2^63的数 //**************************************************************** const int S = 10; //计算x*y%c LL modular_multi(LL x,LL y,LL mo) { LL t; x%=mo; for(t=0;y;x=(x<<1)%mo,y>>=1) if (y&1) t=(t+x)%mo; return t; } //计算num^t%c LL modular_exp(LL num,LL t,LL mo) { LL ret=1,temp=num%mo; for(;t;t>>=1,temp=modular_multi(temp,temp,mo)) if (t&1) ret=modular_multi(ret,temp,mo); return ret; } bool miller_rabbin(LL n) { if (n==2)return true; if (n<2||!(n&1))return false; int t=0; LL a,x,y,u=n-1; while((u&1)==0) t++,u>>=1; for(int i=0;i<S;i++) { a=rand()%(n-1)+1; x=modular_exp(a,u,n); for(int j=0;j<t;j++) { y=modular_multi(x,x,n); if (y==1&&x!=1&&x!=n-1) return false; ///其中用到定理,如果对模n存在1的非平凡平方根,则n是合数。 ///如果一个数x满足方程x^2≡1 (mod n),但x不等于对模n来说1的两个‘平凡’平方根:1或-1,则x是对模n来说1的非平凡平方根 x=y; } if (x!=1)///根据费马小定理,若n是素数,有a^(n-1)≡1(mod n).因此n不可能是素数 return false; } return true; }
//************************************************ //pollard_rho 算法进行质因数分解 //************************************************ long long factor[100];//质因数分解结果(刚返回时是无序的) int tol;//质因数的个数。数组小标从0开始 long long gcd(long long a,long long b) { if(a==0)return 1;//??????? if(a<0) return gcd(-a,b); while(b) { long long t=a%b; a=b; b=t; } return a; } long long Pollard_rho(long long x,long long c) { long long i=1,k=2; long long x0=rand()%x; long long y=x0; while(1) { i++; x0=(modular_multi(x0,x0,x)+c)%x; long long d=gcd(y-x0,x); if(d!=1&&d!=x) return d; if(y==x0) return x; if(i==k){y=x0;k+=k;} } } //对n进行素因子分解 void findfac(long long n) { if(miller_rabbin(n))//素数 { factor[tol++]=n; return; } long long p=n; while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1); findfac(p); findfac(n/p); }
求1~n的素数的个数1e11
#define MAXN 100 // pre-calc max n for phi(m, n) #define MAXM 10010 // pre-calc max m for phi(m, n) #define MAXP 40000 // max primes counter #define MAX 400010 // max prime #define setbit(ar, i) (((ar[(i) >> 6]) |= (1 << (((i) >> 1) & 31)))) #define chkbit(ar, i) (((ar[(i) >> 6]) & (1 << (((i) >> 1) & 31)))) #define isprime(x) (( (x) && ((x)&1) && (!chkbit(ar, (x)))) || ((x) == 2)) long long n; long long dp[MAXN][MAXM]; unsigned int ar[(MAX >> 6) + 5] = { 0 }; int len = 0, primes[MAXP], counter[MAX]; void Sieve() { setbit(ar, 0), setbit(ar, 1); for (int i = 3; (i * i) < MAX; i++, i++) { if (!chkbit(ar, i)) { int k = i << 1; for (int j = (i * i); j < MAX; j += k) setbit(ar, j); } } for (int i = 1; i < MAX; i++) { counter[i] = counter[i - 1]; if (isprime(i)) primes[len++] = i, counter[i]++; } } void init() { Sieve(); for (int n = 0; n < MAXN; n++) { for (int m = 0; m < MAXM; m++) { if (!n) dp[n][m] = m; else dp[n][m] = dp[n - 1][m] - dp[n - 1][m / primes[n - 1]]; } } } long long phi(long long m, int n) { if (n == 0) return m; if (primes[n - 1] >= m) return 1; if (m < MAXM && n < MAXN) return dp[n][m]; return phi(m, n - 1) - phi(m / primes[n - 1], n - 1); } long long Lehmer(long long m) { if (m < MAX) return counter[m]; long long res = 0; int i, a, s, c, y; s = sqrt(0.9 + m), y = c = cbrt(0.9 + m); a = counter[y], res = phi(m, a) + a - 1; for (i = a; primes[i] <= s; i++) res = res - Lehmer(m / primes[i]) + Lehmer(primes[i]) - 1; return res; }
计算二次剩余
/********************************* 计算二次剩余模版即x^2 = n(mod)p *********************************/ typedef long long ll; ll tmod; ll mod(ll n,ll p) { ll temp = 1; while(p > 0) { if(p & 1) temp = temp * n % tmod; n = n * n % tmod; p >>= 1; } return temp; } ll pows(ll n) { ll i; ll temp = 1; for(i = 0; i < n; i++) temp *= 2; return temp; } int main() { int n,p,cs; ll z,q,s,c; ll r,t,m,b,i; ll minx; scanf("%d",&cs); while(cs--) { scanf("%d%d",&n,&p); //p=2时特判 if(p == 2) { if(n % p == 1)printf("1\n"); else printf("No root\n"); continue; } //如果无解 tmod = p; if(mod(n,(p - 1) / 2) != 1) { printf("No root\n"); continue; } q = p - 1; s = 0; while(q % 2 == 0) { q /= 2; s ++; } if(s == 1) { r = mod(n,(p + 1) / 4); } else { while(1) { z = 1 + rand() % (p - 1); if(mod(z,(p - 1) / 2) == (p - 1)) break; } c = mod(z,q); r = mod(n,(1 + q) / 2); t = mod(n,q); m = s; while(1) { if(t % p == 1) break; for(i = 1; i < m; i++) { if(mod(t,pows(i)) == 1) break; } b = mod(c, pows(m - i - 1)); r = r * b % p; t = t * b * b % p; c = b * b % p; m = i; } } r = (r % p + p) % p; //如果只有一个 if(r == p - r)cout<<r<<endl; //如果有两个按照升序输出 else { minx = min(r,p - r); cout<<minx<<" "<<(p - minx)<<endl; } } return 0; }
计算离散对数
/************************************* *baby_step giant_step *应用条件n必须为素数 *a^x = b (mod n) ,a,b < n *求解上式 0<=x < n的解 *************************************/ const int MOD = 76543; int hs[MOD],head[MOD],Next[MOD],id[MOD],top; void Insert(int x,int y) { int k = x%MOD; hs[top] = x, id[top] = y, Next[top] = head[k], head[k] = top++; } int Find(int x) { int k = x%MOD; for(int i = head[k]; i != -1; i = Next[i]) if(hs[i] == x) return id[i]; return -1; } int BSGS(int a,int b,int n) { memset(head,-1,sizeof(head)); top = 1; if(b == 1)return 0; int m = sqrt(n*1.0), j; long long x = 1, p = 1; for(int i = 0; i < m; ++i, p = p*a%n)Insert(p*b%n,i); for(long long i = m; ;i += m) { if( (j = Find(x = x*p%n)) != -1 )return i-j;//找到了可行解 if(i > n)break; } //如果无解 return -1; }
原根
哪些数有原根?
原根的一些性质:
•一个数n如果有原根,那么有
•高斯证明了:
•一个数n的全体原根乘积模n余1
•一个数n的全体原根总和模n余μ(n-1)(莫比乌斯函数)
求出n的所有原根,不存在原根输出-1
const int N = 1000000; bool f[N]; int phi(int x){ if(f[x]) return x-1; int ans = x; for(int i=2; i<=x; i++){ if(x%i==0){ while(x%i==0) x/=i; ans = ans - ans/i; } } if(x>1) ans = ans - ans/x; return ans; } int gcd(int a, int b){ swap(a,b); int c = a%b; while(c){ a=b; b=c; c=a%b; } return b; } int quick_mod(int x, int p, int mod){ long long s = 1; long long a = x; while(p){ if(p&1) s = (s*a)%mod; a = a*a%mod; p>>=1; } return (int)s; } vector<int> V; vector<int> G; void cal(int x){ G.clear(); if(f[x]) return; else{ for(int i=2; i*i<=x; i++){ if(x%i==0){ G.push_back(i); if(i*i!=x) G.push_back(x/i); } } } } bool exist(int n){ if(n%2==0) n/=2; if(f[n]) return 1; for(int i=3; i*i<=n; i+=2){ if(n%i==0){ while(n%i==0) n/=i; return n==1; } } return 0; } void solve(int n){ if(n==2){ puts("1"); return; } if(n==4){ puts("3"); return; } if(!exist(n)){ puts("-1"); return; } int p = phi(n); cal(p); int x = -1; for(int i=2; i<n; i++){ bool flag = 1; if(quick_mod(i, p, n)!=1) continue; for(int j=0; j<G.size(); j++){ if(quick_mod(i, G[j], n)==1){ flag = 0; break; } } if(flag){ V.resize(1); V[0] = x = i; break; } } if(x==-1){ puts("-1"); return; } for(int i=2; i<p; i++){ if(gcd(i, p)==1) V.push_back(quick_mod(x, i, n)); } sort(V.begin(), V.end()); vector<int>::iterator it=unique(V.begin(), V.end()); V.erase(it, V.end()); for(int i=0; i<V.size(); i++){ if(i) putchar(' '); printf("%d", V[i]); } puts(""); } int main(){ memset(f, 1, sizeof(f)); f[0] = f[1] = 0; for(int i=2; i<N; i++){ if(f[i]){ for(int j=i<<1; j<N; j+=i) f[j]=0; } } int n; while(~scanf("%d", &n)) solve(n); return 0; }
组合数学
n球m盒分配问题
第一类斯特林数:
把一个包含n个元素的集合分成k个环排列的方法数。
s[1][1] = 1; for(int i = 2; i <= 20; ++i) for(int j = 1; j <= i; ++j) { s[i][j] = s[i-1][j-1] + s[i-1][j]*(i-1); }
第二类斯特林数:
把一个包含n个元素的集合分成k个非空子集的方法数。
for(int i = 1; i <= 2000; ++i) { s[i][1] = 1; for(int j = 2; j <= i; ++j) { s[i][j] = s[i-1][j-1] + j*s[i-1][j]; } }
Lucas定理:
n,m比较大,p可能为和数。
LL quick_mod(LL a, LL b) { LL ans = 1; a %= p; while(b) { if(b & 1) { ans = ans * a % p; b--; } b >>= 1; a = a * a % p; } return ans; } LL C(LL n, LL m) { if(m > n) return 0; LL ans = 1; for(int i=1; i<=m; i++) { LL a = (n + i - m) % p; LL b = i % p; ans = ans * (a * quick_mod(b, p-2) % p) % p; } return ans; } LL Lucas(LL n, LL m) { if(m == 0) return 1; return C(n % p, m % p) * Lucas(n / p, m / p) % p; }
阅读全文
0 0
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- 数论总结
- ACM数论总结
- ACM数论总结
- 数论总结1
- 数论学习总结
- 数论学习总结2
- 数论模板总结
- 数论学习总结《一》
- 使用Akka的远程调用
- CardView轻松实现圆角卡片效果
- TreeSet添加自定义元素(比较)
- 【hibernate】查询方式与区别
- php代码优化技巧
- 数论总结
- HTML5-ES6
- 8个重要的电子邮件黑名单及如何从黑名单中删除?
- 生产者与消费者模型
- HDU 2457 || POJ 3691 DNA repair (AC自动机 + dp)
- 基于MapReduce框架的K-means算法实现
- STL之Queue
- 单调递增最长子序列
- python 命令行参数解析的标准模板