赞
踩
数论在蓝桥杯上考的不多,但是这不能否定它的重要性。
1.简单的GCD的应用:
分析一下,由等差数列的性质,个数=(an-a1)/d+1,其中an与a1是固定的,因此我们就是让dmax,我们先排一下序,d就是相邻两个数差的gcd,(注意特判0的情况),同时为了方便求,我们让它与a[0]做差即可(答案显然是对的,可以用欧几里得想一想)
下面是AC代码:
- #include<bits/stdc++.h>
- using namespace std;
- const int N=100010;
- int a[N],n;
- int gcd(int a,int b){
- return b? gcd(b,a%b):a;
- }
- int main(){
- cin>>n;
- for(int i=0;i<n;i++) scanf("%d",&a[i]);
- sort(a,a+n);
- int d=0;
- for(int i=1;i<n;i++) d=gcd(d,a[i]-a[0]);
- if(d) cout<<(a[n-1]-a[0])/d+1;
- else cout<<n;
- }
2.算数基本定理的应用:
首先我们假设X由a1个质数p1以及a2个质数p2组成,那么我们第一个一定是选一个p1/p2,那么下一个呢?我们要让倍数尽量的小,假如我们乘合数,那么它一定可以分成跟小的质数,假如质数不存在就不选,否则就乘质数,因此我们可以得到一个结论:每次乘p1\p2,因此长度就是a1+a2。
至于个数,就是(a1+a2)!/(a1!*a2!)(高中排列的消序操作)。
这样我们就可以用欧拉筛愉快的AC了:
- #include<bits/stdc++.h>
- using namespace std;
- const int N=(1<<20)+10;
- int primes[N],cnt,x;
- bool st[N];
- int minp[N];
- void pp(int n){
- for(int i=2;i<=n;i++){
- if(!st[i]) minp[i]=i,primes[cnt++]=i;
- for(int j=0;primes[j]*i<=n;j++){
- st[primes[j]*i]=1;//删的一定是合数
- minp[primes[j]*i]=primes[j];
- if(i%primes[j]==0) break;//prime[j]一定小于i的最小质因子,保证删合数一定是用其最小质因子,也保证每一个合数一定被删
- }
- }
- }
- int main(){
- pp(N-1);
- int fact[30],sum[N];
- while(scanf("%d",&x)!=-1){
- int k=0;
- int tot=0;
- while(x>1){
- int p=minp[x];
- fact[k]=p,sum[k]=0;
- while(x%p==0){
- x/=p;
- tot++;
- sum[k]++;
- }
- k++;
- }
- long long ans=1;
- for(int i=1;i<=tot;i++) ans*=i;
- for(int i=0;i<k;i++){
- for(int j=1;j<=sum[i];j++){
- ans/=j;
- }
- }
- cout<<tot<<" "<<ans<<endl;
- }
-
- }
3.DFS+约数定理+剪枝:
首先对于一个数,它的正约数之和为(1+p1+p1^2+...)(1+p2+p2^2...)(.....)=s
我们发现这样的数其实很少,于是我们考虑DFS+剪枝:
我们每一轮DFS去枚举p以及幂,若整除则枚举下一层,那么如何剪枝?
我们不妨特判(把表达式分一下类),我们发现当a1==1时S=1+Pi,即S-1一定是质数,否则的话一定是偶数(提一个p).
假如S-1为质数,我们就可以得到答案了。
否则,S-1=(1+pi)(1+pj+..)(..)或(1+pi+pi^2)....
对于第一种pi*pj<pi^2,因此我们只要枚举到根号S即可。
这样子就巧妙地从枚举p从2---S到了根号S。
下面是AC代码:
- #include<bits/stdc++.h>
- using namespace std;
- const int N=50000;
- int primes[N],cnt,x,len,ans[N];
- bool st[N];
- int minp[N];
- void pp(int n){
- for(int i=2;i<=n;i++){
- if(!st[i]) minp[i]=i,primes[cnt++]=i;
- for(int j=0;primes[j]*i<=n;j++){
- st[primes[j]*i]=1;//删的一定是合数
- minp[primes[j]*i]=primes[j];
- if(i%primes[j]==0) break;//prime[j]一定小于i的最小质因子,保证删合数一定是用其最小质因子,也保证每一个合数一定被删
- }
- }
- }
- bool check(int x){
- if(x<N) return !st[x];
- for(int i=0;primes[i]<=x/primes[i];i++){
- if(x%primes[i]==0) return 0;
- }
- return 1;
- }
- void dfs(int last,int po,int s){
- if(s==1){//完成
- ans[len++]=po;
- return;
- }
- if(s-1>(last<0?1:primes[last])&&check(s-1)){
- ans[len++]=po*(s-1);//完成但是不唯一,因此不return
- }
- for(int i=last+1;primes[i]<=s/primes[i];i++){//防止暴int
- int p=primes[i];
- for(int j=1+p,t=p;j<=s;t*=p,j+=t){
- if(s%j==0) dfs(i,po*t,s/j);
- }
- }
-
- }
- int main(){
- pp(N-1);
- int s;
- while(cin>>s){
- len=0;
- dfs(-1,1,s);//上一次的下标,当前正确数,剩余的数。
- cout<<len<<endl;
- if(len){
- sort(ans,ans+len);
- for(int i=0;i<len;i++){
- printf("%d ",ans[i]);
- }
- cout<<endl;
- }
- }
- }
4.扩展欧几里得算法的简单应用:
具体内容已经写过,这里就不介绍了,这里就放几张图当复习(这个感觉更好理解):
x+bd=y(mod n)
-an+bd=y-x,其中n,d固定,y-x也是常数,我们只要看看y-x是否是gcd的倍数即可。
答案是b=b0+k*n/gcd(n,d)即b0mod(n/gcd(n,d))
下面是AC代码:
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long LL;
- LL exgcd(LL a,LL b,LL &x,LL &y){
- if(!b){
- x=1,y=0;
- return a;
- }
- LL d=exgcd(b,a%b,y,x);
- y-=a/b*x;
- return d;
- }
- int main(){
- int t;
- cin>>t;
- while(t--){
- LL n,d,x,y,a,b;
- scanf("%lld%lld%lld%lld",&n,&d,&x,&y);
- int gcd=exgcd(n,d,a,b);
- if((y-x)%gcd) cout<<"Impossible"<<endl;
- else{
- b*=(y-x)/gcd;
- n/=gcd;
- printf("%lld\n",(b%n+n)%n);
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。