这一场两个和大数有关的题目,都用到了米勒拉宾算法,有点东西,备忘一下。
F. Divisions
这个题是求一个数的所有因子个数,但是数据比较大,1e18,所以是大数的题目,正常的求因数的或者求质因数的都过不了,因为这一场的K是米勒拉宾判大素数,先过的K题,所以这个题直接头铁用Miller_Rabin+Pollard_rho这两个东西+因子个数求解公式写过去了。
这两个算法的具体原理不清楚。从别人那里知道了一点。
Miller_Rabin算法的作用是判断一个数是否是个素数,算法速度很快,虽然是概率算法,有一定误判概率,不过可以多次运算大幅度减少误判,误判概率与运算次数t有关,为2^(-t);当t够大时,误判的可能性就很小了。
Pollard_rho算法作用是求一个数的因子,这个复杂度为O(sqrt(p)),p为这个数的因子。
参考来自别的的博客,传送门:算法集锦(特殊模板集)
因为Miller_Rabin+Pollard_rho这两个东西求出来的是一个数的所有质因数,所以最后要用因数个数求解公式来算出来结果。
关于因数个数求解公式:
对于任何一个自然数N,都可以分解质因子得到如下形式:
那么,N的因子的个数为:
如N=100,分解质因子变形为:100=22∗52,N的因子的个数为:f(N)=f(100)=(1+2)∗(1+2)=9。
即:1,2,4,5,10,20,25,50,100。
特判一下1就可以,找出来素因子之后,我是用map记了一下数然后用因子个数求解公式得到的结果。其他的没什么了。
代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<math.h> 8 #include<cstdlib> 9 #include<set> 10 #include<map> 11 #include<ctime> 12 #include<stack> 13 #include<queue> 14 #include<vector> 15 #include<set> 16 using namespace std; 17 typedef long long ll; 18 const ll NUM=10;//运算次数,Miller_Rabin算法为概率运算,误判率为2^(-NUM); 19 ll t,f[100]; 20 ll mul_mod(ll a,ll b,ll n)//求a*b%n,由于a和b太大,需要用进位乘法 21 { 22 a=a%n; 23 b=b%n; 24 ll s=0; 25 while(b) 26 { 27 if(b&1) 28 s=(s+a)%n; 29 a=(a<<1)%n; 30 b=b>>1; 31 } 32 return s; 33 } 34 ll pow_mod(ll a,ll b,ll n)//求a^b%n 35 { 36 a=a%n; 37 ll s=1; 38 while(b) 39 { 40 if(b&1) 41 s=mul_mod(s,a,n); 42 a=mul_mod(a,a,n); 43 b=b>>1; 44 } 45 return s; 46 } 47 bool check(ll a,ll n,ll r,ll s) 48 { 49 ll ans=pow_mod(a,r,n); 50 ll p=ans; 51 for(ll i=1;i<=s;i++) 52 { 53 ans=mul_mod(ans,ans,n); 54 if(ans==1&&p!=1&&p!=n-1) 55 return true; 56 p=ans; 57 } 58 if(ans!=1) return true; 59 return false; 60 } 61 bool Miller_Rabin(ll n)//Miller_Rabin算法,判断n是否为素数 62 { 63 if(n<2) return false; 64 if(n==2) return true; 65 if(!(n&1)) return false; 66 ll r=n-1,s=0; 67 while(!(r&1)){r=r>>1;s++;} 68 for(ll i=0;i<NUM;i++) 69 { 70 ll a=rand()%(n-1)+1; 71 if(check(a,n,r,s)) 72 return false; 73 } 74 return true; 75 } 76 ll gcd(ll a,ll b) 77 { 78 return b==0?a:gcd(b,a%b); 79 } 80 ll Pollard_rho(ll n,ll c)//Pollard_rho算法,找出n的因子 81 { 82 ll i=1,j,k=2,d,p; 83 ll x=rand()%n; 84 ll y=x; 85 while(true) 86 { 87 i++; 88 x=(mul_mod(x,x,n)+c)%n; 89 if(y==x) return n; 90 if(y>x) p=y-x; 91 else p=x-y; 92 d=gcd(p,n); 93 if(d!=1&&d!=n) return d; 94 if(i==k) 95 { 96 y=x; 97 k+=k; 98 } 99 } 100 } 101 void find(ll n)//找出n的所有因子 102 { 103 if(Miller_Rabin(n)) 104 { 105 f[t++]=n;//保存所有因子 106 return; 107 } 108 ll p=n; 109 while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);//由于p必定为合数,所以通过多次求解必定能求得答案 110 find(p); 111 find(n/p); 112 } 113 int main() 114 { 115 srand(time(NULL));//随机数设定种子 116 ll n;cin>>n; 117 if(n==1){cout<<"1"<<endl;return 0;} 118 t=0; 119 find(n); 120 sort(f,f+t); 121 map<ll,int>q; 122 for(int i=0;i<t;i++) 123 { 124 q[f[i]]++; 125 } 126 map<ll,int>::iterator it; 127 ll ans=1; 128 for(it=q.begin();it!=q.end();it++) 129 { 130 int s=it->second; 131 ans*=1+s; 132 } 133 cout<<ans<<endl; 134 return 0; 135 }
E. Change of Scenery
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int maxn=1e5+10; 8 int a[maxn]; 9 int main(){ 10 int n; 11 scanf("%d",&n); 12 for(int i=0;i<n;i++) 13 scanf("%d",&a[i]); 14 for(int i=1;i<n;i++){ 15 if(a[i]<a[i-1]){ 16 cout<<"no"<<endl; 17 return 0; 18 } 19 } 20 cout<<"yes"<<endl; 21 }
K. Upside down primes
这个题就是把大数按字符串输进去,判断一下是不是素数,然后反转180度,先判断反转之后的东西是不是一个数,如果是的话,再把这个数判一下是不是素数,如果都满足条件就yes。
直接调用两次米勒拉宾判大素数就可以了。
代码:
1 //K-米勒拉宾判大素数 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<iomanip> 6 #include<stdio.h> 7 #include<stdlib.h> 8 #include<math.h> 9 #include<cstdlib> 10 #include<set> 11 #include<map> 12 #include<ctime> 13 #include<stack> 14 #include<queue> 15 #include<vector> 16 #include<set> 17 using namespace std; 18 typedef long long ll; 19 #define INF 0x7fffffff 20 #define LIT 0x3f3f3f3f 21 #define me(a,b) memset(a,b,sizeof(a)) 22 #define PI acos(-1.0) 23 #define ios ios::sync_with_stdio(0),cin.tie(0); 24 const int N=1e5+5; 25 const int maxn=1e9; 26 const int S=20; 27 ll sw(ll a) 28 { 29 if(a==0||a==2||a==5||a==8||a==1) 30 return a; 31 if(a==6) 32 return 9; 33 if(a==9) 34 return 6; 35 else 36 return -1; 37 } 38 ll mult_mod(ll a,ll b,ll mod) 39 { 40 a%=mod;b%=mod; 41 ll ans=0; 42 while(b) 43 { 44 if(b&1) 45 { 46 ans=ans+a; 47 if(ans>=mod) 48 ans=ans-mod; 49 } 50 a=a<<1; 51 if(a>=mod) a=a-mod; 52 b=b>>1; 53 } 54 return ans; 55 } 56 ll pow_mod(ll a,ll b,ll mod) 57 { 58 ll ans=1; 59 a=a%mod; 60 while(b) 61 { 62 if(b&1) 63 { 64 ans=mult_mod(ans,a,mod); 65 } 66 a=mult_mod(a,a,mod); 67 b=b>>1; 68 } 69 return ans; 70 } 71 bool check(ll a,ll n,ll x,ll t) 72 { 73 ll ret=pow_mod(a,x,n); 74 ll last=ret; 75 for(int i=1;i<=t;i++) 76 { 77 ret=mult_mod(ret,ret,n); 78 if(ret==1&&last!=1&&last!=n-1) 79 return true; 80 last=ret; 81 } 82 if(ret!=1) return true; 83 else return false; 84 } 85 bool Miller_Rabin(ll n) 86 { 87 if(n<2)return false; 88 if(n==2) return true; 89 if((n&1)==0) return false; 90 ll x=n-1,t=0; 91 while((x&1)==0){x>>=1;t++;} 92 for(int i=0;i<S;i++) 93 { 94 ll a=rand()%(n-1)+1; 95 if(check(a,n,x,t)) 96 return false; 97 } 98 return true; 99 } 100 char ch[20]; 101 int main() 102 { 103 cin>>ch; 104 ll n=0,bit=1; 105 int len=strlen(ch); 106 bool flag=false; 107 for(int i=len-1;i>=0;i--) 108 { 109 n+=(ch[i]-'0')*bit; 110 bit*=10; 111 } 112 if(!Miller_Rabin(n)) 113 { 114 cout<<"no"<<endl; 115 return 0; 116 } 117 n=0;bit=1; 118 for(int i=0;i<len;i++){ 119 ll cnt=sw(ch[i]-'0'); 120 if(cnt==-1){ 121 cout<<"no"<<endl; 122 return 0; 123 } 124 n+=cnt*bit; 125 bit*=10; 126 } 127 if(Miller_Rabin(n)) 128 cout<<"yes"<<endl; 129 else 130 cout<<"no"<<endl; 131 }
就这些,没了。
因为这场没找到数据结构的题,就和一个队友一起刚了数论题,这场主要是图论和数论。难过,图论选手不理我,是真的回家休息去了,上一场比赛的A题和这场的图论题都比较好,如果,你能看到的话,可以去看看这些题,正好和你最近学的算法有关系。
唉,算了,都讨厌死我了。
就这些,备忘一下,米勒拉宾有点厉害。
最近在慢慢改代码风格,因为我发现队友们写代码都是把大括号对齐了写,现在再改回来。
继续去爱我的线段树去了,我滚了。
对于任何一个自然数N,都可以分解质因子得到如下形式:
那么,N的因子的个数为:
如N=100,分解质因子变形为:100=22∗52,N的因子的个数为:f(N)=f(100)=(1+2)∗(1+2)=9。
即:1,2,4,5,10,20,25,50,100。
特判一下1就可以,找出来素因子之后,我是用map记了一下数然后用因子个数求解公式得到的结果。其他的没什么了。
代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<math.h> 8 #include<cstdlib> 9 #include<set> 10 #include<map> 11 #include<ctime> 12 #include<stack> 13 #include<queue> 14 #include<vector> 15 #include<set> 16 using namespace std; 17 typedef long long ll; 18 const ll NUM=10;//运算次数,Miller_Rabin算法为概率运算,误判率为2^(-NUM); 19 ll t,f[100]; 20 ll mul_mod(ll a,ll b,ll n)//求a*b%n,由于a和b太大,需要用进位乘法 21 { 22 a=a%n; 23 b=b%n; 24 ll s=0; 25 while(b) 26 { 27 if(b&1) 28 s=(s+a)%n; 29 a=(a<<1)%n; 30 b=b>>1; 31 } 32 return s; 33 } 34 ll pow_mod(ll a,ll b,ll n)//求a^b%n 35 { 36 a=a%n; 37 ll s=1; 38 while(b) 39 { 40 if(b&1) 41 s=mul_mod(s,a,n); 42 a=mul_mod(a,a,n); 43 b=b>>1; 44 } 45 return s; 46 } 47 bool check(ll a,ll n,ll r,ll s) 48 { 49 ll ans=pow_mod(a,r,n); 50 ll p=ans; 51 for(ll i=1;i<=s;i++) 52 { 53 ans=mul_mod(ans,ans,n); 54 if(ans==1&&p!=1&&p!=n-1) 55 return true; 56 p=ans; 57 } 58 if(ans!=1) return true; 59 return false; 60 } 61 bool Miller_Rabin(ll n)//Miller_Rabin算法,判断n是否为素数 62 { 63 if(n<2) return false; 64 if(n==2) return true; 65 if(!(n&1)) return false; 66 ll r=n-1,s=0; 67 while(!(r&1)){r=r>>1;s++;} 68 for(ll i=0;i<NUM;i++) 69 { 70 ll a=rand()%(n-1)+1; 71 if(check(a,n,r,s)) 72 return false; 73 } 74 return true; 75 } 76 ll gcd(ll a,ll b) 77 { 78 return b==0?a:gcd(b,a%b); 79 } 80 ll Pollard_rho(ll n,ll c)//Pollard_rho算法,找出n的因子 81 { 82 ll i=1,j,k=2,d,p; 83 ll x=rand()%n; 84 ll y=x; 85 while(true) 86 { 87 i++; 88 x=(mul_mod(x,x,n)+c)%n; 89 if(y==x) return n; 90 if(y>x) p=y-x; 91 else p=x-y; 92 d=gcd(p,n); 93 if(d!=1&&d!=n) return d; 94 if(i==k) 95 { 96 y=x; 97 k+=k; 98 } 99 } 100 } 101 void find(ll n)//找出n的所有因子 102 { 103 if(Miller_Rabin(n)) 104 { 105 f[t++]=n;//保存所有因子 106 return; 107 } 108 ll p=n; 109 while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);//由于p必定为合数,所以通过多次求解必定能求得答案 110 find(p); 111 find(n/p); 112 } 113 int main() 114 { 115 srand(time(NULL));//随机数设定种子 116 ll n;cin>>n; 117 if(n==1){cout<<"1"<<endl;return 0;} 118 t=0; 119 find(n); 120 sort(f,f+t); 121 map<ll,int>q; 122 for(int i=0;i<t;i++) 123 { 124 q[f[i]]++; 125 } 126 map<ll,int>::iterator it; 127 ll ans=1; 128 for(it=q.begin();it!=q.end();it++) 129 { 130 int s=it->second; 131 ans*=1+s; 132 } 133 cout<<ans<<endl; 134 return 0; 135 }
E. Change of Scenery
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int maxn=1e5+10; 8 int a[maxn]; 9 int main(){ 10 int n; 11 scanf("%d",&n); 12 for(int i=0;i<n;i++) 13 scanf("%d",&a[i]); 14 for(int i=1;i<n;i++){ 15 if(a[i]<a[i-1]){ 16 cout<<"no"<<endl; 17 return 0; 18 } 19 } 20 cout<<"yes"<<endl; 21 }
K. Upside down primes
这个题就是把大数按字符串输进去,判断一下是不是素数,然后反转180度,先判断反转之后的东西是不是一个数,如果是的话,再把这个数判一下是不是素数,如果都满足条件就yes。
直接调用两次米勒拉宾判大素数就可以了。
代码:
1 //K-米勒拉宾判大素数 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<iomanip> 6 #include<stdio.h> 7 #include<stdlib.h> 8 #include<math.h> 9 #include<cstdlib> 10 #include<set> 11 #include<map> 12 #include<ctime> 13 #include<stack> 14 #include<queue> 15 #include<vector> 16 #include<set> 17 using namespace std; 18 typedef long long ll; 19 #define INF 0x7fffffff 20 #define LIT 0x3f3f3f3f 21 #define me(a,b) memset(a,b,sizeof(a)) 22 #define PI acos(-1.0) 23 #define ios ios::sync_with_stdio(0),cin.tie(0); 24 const int N=1e5+5; 25 const int maxn=1e9; 26 const int S=20; 27 ll sw(ll a) 28 { 29 if(a==0||a==2||a==5||a==8||a==1) 30 return a; 31 if(a==6) 32 return 9; 33 if(a==9) 34 return 6; 35 else 36 return -1; 37 } 38 ll mult_mod(ll a,ll b,ll mod) 39 { 40 a%=mod;b%=mod; 41 ll ans=0; 42 while(b) 43 { 44 if(b&1) 45 { 46 ans=ans+a; 47 if(ans>=mod) 48 ans=ans-mod; 49 } 50 a=a<<1; 51 if(a>=mod) a=a-mod; 52 b=b>>1; 53 } 54 return ans; 55 } 56 ll pow_mod(ll a,ll b,ll mod) 57 { 58 ll ans=1; 59 a=a%mod; 60 while(b) 61 { 62 if(b&1) 63 { 64 ans=mult_mod(ans,a,mod); 65 } 66 a=mult_mod(a,a,mod); 67 b=b>>1; 68 } 69 return ans; 70 } 71 bool check(ll a,ll n,ll x,ll t) 72 { 73 ll ret=pow_mod(a,x,n); 74 ll last=ret; 75 for(int i=1;i<=t;i++) 76 { 77 ret=mult_mod(ret,ret,n); 78 if(ret==1&&last!=1&&last!=n-1) 79 return true; 80 last=ret; 81 } 82 if(ret!=1) return true; 83 else return false; 84 } 85 bool Miller_Rabin(ll n) 86 { 87 if(n<2)return false; 88 if(n==2) return true; 89 if((n&1)==0) return false; 90 ll x=n-1,t=0; 91 while((x&1)==0){x>>=1;t++;} 92 for(int i=0;i<S;i++) 93 { 94 ll a=rand()%(n-1)+1; 95 if(check(a,n,x,t)) 96 return false; 97 } 98 return true; 99 } 100 char ch[20]; 101 int main() 102 { 103 cin>>ch; 104 ll n=0,bit=1; 105 int len=strlen(ch); 106 bool flag=false; 107 for(int i=len-1;i>=0;i--) 108 { 109 n+=(ch[i]-'0')*bit; 110 bit*=10; 111 } 112 if(!Miller_Rabin(n)) 113 { 114 cout<<"no"<<endl; 115 return 0; 116 } 117 n=0;bit=1; 118 for(int i=0;i<len;i++){ 119 ll cnt=sw(ch[i]-'0'); 120 if(cnt==-1){ 121 cout<<"no"<<endl; 122 return 0; 123 } 124 n+=cnt*bit; 125 bit*=10; 126 } 127 if(Miller_Rabin(n)) 128 cout<<"yes"<<endl; 129 else 130 cout<<"no"<<endl; 131 }
就这些,没了。
因为这场没找到数据结构的题,就和一个队友一起刚了数论题,这场主要是图论和数论。难过,图论选手不理我,是真的回家休息去了,上一场比赛的A题和这场的图论题都比较好,如果,你能看到的话,可以去看看这些题,正好和你最近学的算法有关系。
唉,算了,都讨厌死我了。
就这些,备忘一下,米勒拉宾有点厉害。
最近在慢慢改代码风格,因为我发现队友们写代码都是把大括号对齐了写,现在再改回来。
继续去爱我的线段树去了,我滚了。