集训2:数学专题:整数的分解和萨筛法

 1.欧几里得拓展及应用

拓展欧几里得就是求形如ax+by=gcd(a,b)的解,应用可以求ax+by=c二元一次方程组的解;如果c是gcd(a,b)的倍数才有解

1.

        temp=x;

        x=y;

        y=temp-(b/a)*y;

2.

        x=x0*(c/gcd);

        t=x/(b/gcd);

        x=x-t*(b/gcd);

if(x<0)x=x+b/gcd;

    

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll x,y,m,n,l;//欧几里得tuozhan
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
	if(b==0)
	{
		x=1;y=0;return a;
	}
	ll g=ex_gcd(b,a%b,x,y);
	ll temp=x;
	x=y;
	y=temp-(a/b)*y;
	return g;
} 
int main()
{
	cin>>x>>y>>m>>n>>l;//(m-n)t=(y-x)+kL;
	ll a=m-n,b=l,c=y-x;
	if(m-n<0)
	{
		a=-a;c=-c;
	}
	ll x0,y0;
	ll gcd=ex_gcd(a,b,x0,y0);
	if(c%gcd!=0)
	{
		cout<<"Imposible"<<endl;return 0;
	}
	ll ans;
	ans=x0*(c/gcd);	
	ll t=ans/(b/gcd);
	ans=ans-t*(b/gcd);
	if(ans<=0)ans+=b/gcd;
	cout<<ans<<endl;
	return 0; 
}

 2.连续素数和

用的是前缀和+二分查找

用到了欧拉筛素数

注意long long

 

#include<bits/stdc++.h>
using namespace std;
int t;
int k=0,ans=0;
const int maxn=4e7+10;
int prime[maxn];
int mark[maxn];
long long sum[maxn];
void pinit()
{
	mark[1]=1;
	for(int i=2;i<=maxn;i++)
	{
		if(!mark[i])prime[++k]=i;
		for(int j=1;j<=k&&prime[j]*i<=maxn;j++)
		{
			mark[prime[j]*i]=1;
			if(i%prime[j]==0)break;
		}
	}
	return ;
}
void zhihe()
{
	for(int i=1;i<=k;i++)
	{
	sum[i]=sum[i-1]+prime[i];
	}
}
bool find(int l,int r,long long x)
{
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(sum[mid]==x)return true;
		else if(sum[mid]>x)r=mid-1;
		else l=mid+1;
	}
	return 0;
}
int main()
{
	cin>>t;
	pinit();
	zhihe();sum[0]=0;
	while(t--)
	{
		ans=0;
		int n;
		cin>>n;
		int i=0;
		while(1)
		{
			i++;if(sum[i]>=n)break;
		}
		for(int j=i;prime[j]<=n;j++)
		{
			long long x=sum[j]-n;
			if(find(0,j,x))
			ans++;
		
		}
		cout<<ans<<endl;
		
	}
	return 0;
 } 

3.prime distance

这道题要用到区间素数筛,由于l,r很大,但是r-l却不大

除了用欧拉筛开辟bool vis[50000],prime[50000]两个数组外还开一个bool temp[maxn]和ans[maxn]

temp用来表示l到r区间内的数是否为素数,ans用来记录l到r之间的素数;一般int范围内的数开到根号下2147483647;

vis

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,r,l;
const int maxn=1e6+10;
const int N=5e4;
bool vis[N],temp[maxn];
int prime[N],ans[maxn];
int cnt,cntt;
void init()
{
	memset(vis,0,sizeof(vis));
	cnt=0;
	for(int i=2;i<=N;i++)
	{
		if(!vis[i])prime[++cnt]=i;
		for(int j=1;j<=cnt&&prime[j]*i<=N;j++)
		{
		vis[prime[j]*i]=1;
		if(i%prime[j]==0)break;
		}
	}
}
void prim_e()
{
	memset(temp,0,sizeof(temp));
	for(int i=1;i<=cnt;i++)
	{
		int b=l/prime[i];
		while(b<=1)b++;
		for(int j=b*prime[i];j<=r;j+=prime[i])
		{
			if(l<=j)
			temp[j-l+1]=1;
		}
	}
	if(l==1)temp[1]=1;
	for(int i=1;i<=r-l+1;i++)
	{
		if(!temp[i])ans[++cntt]=i+l-1;
	}
 } 
 int main()
 {
 	cin>>t;
 	init();
 	while(t--)
 	{
 		cntt=0;
 		cin>>l>>r;
 		prim_e();
 		int minp=2,maxp=2;
 		if(cntt<=1)cout<<"There are no adjacent primes."<<endl;
 		else
 		{
 			
 			for(int i=2;i<=cntt;i++)
 			{
 				int d=ans[i]-ans[i-1];
 				if(d<ans[minp]-ans[minp-1])minp=i;
 				if(d>ans[maxp]-ans[maxp-1])maxp=i;
			 }
			 cout<<ans[minp-1]<<","<<ans[minp]<<" are closest, ";
			 cout<<ans[maxp-1]<<","<<ans[maxp]<<" are most distant."<<endl;
		 }
	 }
	 return 0;
 }

4.prime land

我是直接模拟出来的,不过题目中这个公式挺重要的

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
int t,k;
int n,cnt;
bool vis[maxn];
int prime[maxn];
int p[maxn],e[maxn];
int qiun()
{
	int n=1;
	for(int i=1;i<=k;i++)
	n=n*pow(p[i],e[i]);
	return n-1;
}
void prim_e()
{
	cnt=0;
	memset(vis,0,sizeof(vis));
	vis[1]=1;
	for(int i=2;i<=maxn;i++)
	{
		if(!vis[i])prime[++cnt]=i;
		for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
		{
		vis[prime[j]*i]=1;
		if(!i%prime[j])break;
		}
	}
}
void answer(int y)
{
	if(!vis[y])
	{
		cout<<y<<" "<<1<<endl;
		return ;
	 } 
	int i=1;
	while(prime[i]<y)
	i++;//找到最大的那个 
	for(int j=i;y!=1&&j>=1;j--)
	{
		int e=0;
		while(y%prime[j]==0)
		{
			y=y/prime[j];
			e++;
		}
		if(e) 
		cout<<prime[j]<<" "<<e<<" ";
	}
	cout<<endl;
}
int main()
{
	cin>>t;
	prim_e();
	while(t--)
	{
		cin>>k;
		for(int i=1;i<=k;i++)
		cin>>p[i]>>e[i];
		int u=qiun();
		answer(u);
	}
	return 0;
}

 5.x-factor

找到题目的本质是求一个数的最大质因子个数第二个是求所有质因子全排列,注意要去掉重复的情况;

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;


map <int,int> prim_factor(ll n2) {
    map<int,int> maps;
    int N = n2;
    for(int i=2;i*i<=N;i++)  {
        while(n2 % i == 0) {
            maps[i]++;
            n2 /= i;
        }
    }
    if(n2 > 1)
        maps[n2]++;
    return maps;
};

ll mult(int k) {
    ll ans = 1;
    for(int i=2;i<=k;i++)
        ans *= i;
    return ans;
}



int main() {
    ll n;int t;cin>>t;
    while(t--) {
        cin>>n;
        map <int,int> :: iterator iter;
        map <int,int> maps = prim_factor(n);
        int len = 0;
        for(iter=maps.begin();iter!=maps.end();iter++)
            len += iter->second;

        ll ans = mult(len);

        for(iter=maps.begin();iter!=maps.end();iter++)
            ans /= mult(iter->second);
        printf("%d %lld\n",len,ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值