很久没写数论了,现在筛个素数都吃力了,写几道老题熟练一下,顺便弄下今年的模板
第一部分:关于素数
素数是数论里最重要的一种数,很多定理和性质都由素数展开。所以就有人称数论为素论,可见素数在数论中的重要性。/* 计算L,U区间内相邻的差最小的和差最大的两对素数 L,U可能很大,但U-L不大,二次筛素数即可,区间筛素数 */ #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long intt; const int MAXN2 = 1000100; const int MAXN = 47000; int noprime[MAXN],pcnt,p[MAXN]; inline void getprime(){ pcnt = 0; memset(noprime,0,sizeof(noprime)); noprime[0] = noprime[1] = 1; for(int i = 2; i < MAXN; ++i){ if(!noprime[i])p[pcnt++] = i; for(int j = 0; j < pcnt && i*p[j] < MAXN; ++j){ noprime[i*p[j]] = 1; if(i%p[j] == 0)break; } } } intt p2[MAXN2]; int pcnt2,noprime2[MAXN2]; inline void getprime2(intt L,intt U){ pcnt2 = 0; if(U < MAXN){ int s = 0; while (p[s] < L)s++; for(intt i = s; p[i] <= U; ++i)p2[pcnt2++] = p[i]; return; } for(int i = 0; i <= U-L; ++i)noprime2[i] = 0; for(int i = 0; i < pcnt && p[i]*p[i] <= U; ++i){ intt st = L/p[i]; if(L%p[i] == 0)st = L; else st = p[i]*(st+1); for(intt j = st; j <= U; j += p[i]) noprime2[j-L] = 1; } if(L == 1)noprime2[0] = 1; for(intt i = L; i <= U; ++i){ if(!noprime2[i-L])p2[pcnt2++] = i; } } int main(){ intt L,U; getprime(); while (scanf("%lld%lld",&L,&U) != EOF){ getprime2(L,U); if(pcnt2 < 2){ puts("There are no adjacent primes."); continue; } intt ansmax = 0,ima = 0; intt ansmin = U,imi = 0; for(int i = 1; i < pcnt2; ++i){ if(ansmax < p2[i] - p2[i-1]){ ansmax = p2[i] - p2[i-1]; ima = i; } if(ansmin > p2[i] - p2[i-1]){ ansmin = p2[i] - p2[i-1]; imi = i; } } printf("%lld,%lld are closest, %lld,%lld are most distant.\n",p2[imi-1],p2[imi],p2[ima-1],p2[ima]); } return 0; }
/* *两个数n和m,问n!能否整除m *先对m质因数分解,然后判断n!的m中的质因子的数目是不是大于m中该质因子的个数 *这里有个结论:n!中因子p的个数可以这样求: *int t = n,sum = 0; *while ( t > 0 ) { * sum += t / p; * t /= p; *} *sum即为n!中因子p的个数 */ #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 65537; int noprime[MAXN],pcnt,p[MAXN/2]; inline void getprime(){ pcnt = 0; memset(noprime,0,sizeof(noprime)); noprime[0] = noprime[1] = 1; for(int i = 2; i < MAXN; ++i){ if(!noprime[i])p[pcnt++] = i; for(int j = 0; j < pcnt && i*p[j] < MAXN; ++j){ noprime[i*p[j]] = 1; if(i%p[j] == 0)break; } } } int nump[MAXN/2],yinzi[MAXN/2]; int n,m,top; inline void cal(int t){ memset(nump,0,sizeof(nump)); top = -1; int tmp = t; for(int i = 0;i < pcnt && p[i] <= tmp; ++i){ if(t % p[i] == 0){ yinzi[++top] = p[i]; while (t % p[i] == 0){ nump[top] ++; t /= p[i]; } } if(t == 1)break; } if(t > 1){ yinzi[++top] = t; nump[top] ++; } } int main(){ getprime(); while (scanf("%d%d",&n,&m) != EOF){ if(m == 0){ printf("%d does not divide %d!\n", m, n); continue; } cal(m); bool ok = 1; for(int i = 0; i <= top; ++i){ if(yinzi[i] > n){ ok = 0; break; } int t = n,sum = 0; while (t > 0){ sum += t/yinzi[i]; t /= yinzi[i]; if(sum >= nump[i])break; } if(sum < nump[i]){ ok = 0; break; } } if(ok)printf("%d divides %d!\n",m,n); else printf("%d does not divide %d!\n",m,n); } return 0; }
Miller - Rabin素数测试的伪码 Input: n > 2, an odd integer to be tested for primality; k, a parameter that determines the accuracy of the test Output: composite if n is composite, otherwise probably prime write n − 1 as 2^s·d with d odd by factoring powers of 2 from n − 1 LOOP: repeat k times: pick a randomly in the range [2, n − 2] x ← a^d mod n if x = 1 or x = n − 1 then do next LOOP for r = 1 .. s − 1 x ← x^2 mod n if x = 1 then return composite if x = n − 1 then do next LOOP return composite return probably prime
#include <cstdio> #include <cstring> #include <ctime> #include <algorithm> using namespace std; typedef long long bint; const int TIME = 8;//测试次数,8~10够了 int factor[100],fac_top = -1; //计算两个数的gcd inline bint gcd(bint small,bint big){ while(small){ swap(small,big); small%=big; } return big > 0 ? big : -big; } //ret = (a*b)%n (n<2^62) inline bint muti_mod(bint a,bint b,bint n){ bint exp = a%n, res = 0; while(b){ if(b&1){ res += exp; if(res>n) res -= n; } exp <<= 1; if(exp>n) exp -= n; b>>=1; } return res; } // ret = (a^b)%n inline bint mod_exp(bint a,bint p,bint m){ bint exp=a%m, res=1; // while(p>1) { if(p&1)// res=muti_mod(res,exp,m); exp = muti_mod(exp,exp,m); p>>=1; } return muti_mod(res,exp,m); } //miller-rabin法测试素数, time 测试次数O(lonN) inline bool miller_rabin(bint n, int times){ if(n==2)return 1; if(n<2||!(n&1))return 0; bint a, u=n-1, x, y; int t=0; while(u%2==0){ t++; u/=2; } srand(time(0)); for(int i=0;i<times;i++){ a = rand() % (n-1) + 1; x = mod_exp(a, u, n); for(int j=0;j<t;j++){ y = muti_mod(x, x, n); if ( y == 1 && x != 1 && x != n-1 ) return false; //must not x = y; } if( y!=1) return false; } return true; } inline bint pollard_rho(bint n,int c){//找出一个因子 bint x,y,d,i = 1,k = 2; srand(time(0)); x = rand()%(n-1)+1; y = x; while(true) { i++; x = (muti_mod(x,x,n) + c) % n; d = gcd(y-x, n); if(1 < d && d < n)return d; if( y == x) return n; if(i == k) { y = x; k <<= 1; } } } inline void findFactor(bint n,int k){//二分找出所有质因子,存入factor, if(n==1)return; if(miller_rabin(n, TIME)){ factor[++fac_top] = n; return; } bint p = n; while(p >= n) p = pollard_rho(p,k--);//k值变化,防止死循环 findFactor(p,k); findFactor(n/p,k); } int main(){ bint cas,n,min; scanf("%lld",&cas); while(cas--){ scanf("%lld",&n); fac_top = min = -1; if(miller_rabin(n,TIME)) puts("Prime"); else{ findFactor(n,1000); //factor保存该数的所有质因子,0..fac_top for(int i = 0;i <= fac_top;i++){ if(min < 0 || factor[i] < min) min = factor[i]; } printf("%lld\n",min); } } return 0; }