逆元与素数
Posted xiaofengzai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逆元与素数相关的知识,希望对你有一定的参考价值。
A - Detachment
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5976
题解:这道题思路为:数学规律+逆元
这里有一个结论,对于一个数把他拆成从2开始的连续的数,最后得到的成绩是最大的,所以我们可以先预处理一下前缀和包括乘积后的结果。不过对于有些数无法用多个连续的数表示,比如对于11可以找到2+3+4,此时还余2,要构成5还差3,所以我们把3变成5即2 + 4 + 5.
之前是2+3+4
现在是2+4+5
但有种特殊情况,比如2+3+.. + l,此时还余个l,因此我们会为前l-1个数都加上1,还剩余一个1就加到最后一个数,
之前是2+3+4+...l,现在是3+4+5+6+...l+(l+2),对比两者的变化,相当于除去2,在乘上l+2,由于我们要进行取余,因此除法的操作就需要用到逆元(由费马小定理)
代码:
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=50010; ll sum[N],f[N]; void init() { f[1]=1; for(int i=2;i<=N;i++) { sum[i]=sum[i-1]+i; f[i]=(f[i-1]*i)%mod; } } ll pow_s(ll a, ll n) { ll res=1; while(n) { if(n&1) res=res%mod*a%mod; a=a%mod*a%mod; n>>=1; } return res; } int main() { ll i,j,t,x; scanf("%lld",&t); init(); while(t--) { scanf("%lld",&x); if(x<=4) { printf("%lld ",x); continue; } //二分法找到适合的l ll l=0,r=N; while(r-l>1) { ll mid=l+(r-l)/2; if(sum[mid]>x) r=mid; else l=mid; } ll leve=x-sum[l]; ll res=f[l]; if(leve==l) res=(res*pow_s(2,mod-2)%mod*(l+2))%mod; else res=(res*pow_s(l+1-leve,mod-2)%mod*(l+1))%mod; printf("%lld ",res); } return 0; }
B - 寻找素数对
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1262
题解:从这个数的一半的地方开始找,然后进行素数判断,循环即可实现
代码:
#include<iostream> #include<algorithm> #include<cmath> #include<cstdio> using namespace std; int m; bool check(int s) { for(int i=2;i<=sqrt(s);i++) { if(s%i==0) return false; } return true; } int main() { int i,j; while((scanf("%d",&m))!=EOF) { int k=m/2; for(i=k;i>0;i--) { int f=m-i; if(check(f)&&check(i)) { cout<<i<<" "<<f<<endl; break; } } } return 0; }
C - Max Factor
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2710
题解:寻找最大的素数因子,我们可以利用埃式筛求素数的方法,打表找到所有数的最大的素数因子,然后进行比较选出最终的结果。
代码:
#include<iostream> #include<cmath> using namespace std; const int MAXN=1e5; int prime[MAXN+1]; int v[20010]; void aisoup() { for(int i=0;i<=20010;i++) v[i]=1; for(int i=2;i<=20010;i++) { if(v[i]==1) { for(int j=i;j<=20010;j+=i) v[j]=i; } } } int main() { int i,j,n,x,ans,maxn=-1; aisoup(); while(cin>>n) { ans=0; maxn=-1; for(int i=0;i<n;i++) { cin>>x; if(v[x]>maxn) { maxn=v[x]; ans=x; } } cout<<ans<<endl; } return 0; }
D - Twin Prime Conjecture
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3792
题解:题目的意思是找出小于等于他的相邻素数对相差为2的对数,一开始直接利用埃式筛求出素数,然后对于每个数进行一次计算,最终TLE了。
明显这样太过于浪费时间,存在重复计算,因此我们对其进行打表,算出ans数组,它对应的为相应数的素数对个数,而他们之间的关系为,i和i-1之间,比较二者对应的数与相差为2的数是否都为素数。
代码:
#include<iostream> using namespace std; const int N=1e5+10; int prime[N]; bool v[N]; int ans[N]; void pre() { int k=0; for(int i=2;i<N;i++) { if(!v[i]) { prime[k++]=i; for(int j=2*i;j<N;j+=i) { v[j]=true; } } } } void f() { pre(); ans[1]=ans[2]=ans[3]=0; for(int i=4;i<N;i++) { if(!v[i]&&!v[i-2]) { ans[i]=ans[i-1]+1; } else ans[i]=ans[i-1]; } } int main() { f(); int n,i,j; while(cin>>n) { if(n<0) break; cout<<ans[n]<<endl; } return 0; }
E - Squarefree number
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3826
题解:这道题相对来说比较有难度,判断该数的因子当中是否有平方数。我们素数的筛选范围在106范围内,对于这个数的范围为1016次方。
#include<iostream> #include<cmath> #include<cstdio> using namespace std; typedef long long ll; const int N=1e6+10; ll t,n; int prime[N]; bool v[N]; int k; void pre() { k=0; for(int i=2;i<N;i++) { if(!v[i]) { prime[k++]=i; for(int j=i*2;j<N;j+=i) v[j]=true; } } } int main() { ll i,j; cin>>t; pre(); for(i=1;i<=t;i++) { cin>>n; bool flag=false; for(j=0;j<k;j++) { int sum=0; while(n%prime[j]==0) { n/=prime[j]; sum++; } //sum>=2表示有平方数 if(sum>=2) { flag=true; break; } } if(!flag&&n>1) { //判断是否为两个一样大的素数相乘 ll s=sqrt(n); if(s*s==n) flag=true; } if(flag) printf("Case %d: No ",i); else printf("Case %d: Yes ",i); } return 0; }
以上是关于逆元与素数的主要内容,如果未能解决你的问题,请参考以下文章