[洛谷]P1516 青蛙的约会
裴蜀定理(也叫贝祖定理)
设a,b是不全为零的整数,则存在整数x,y, 使得ax+by=gcd(a,b); .
拓展欧几里得算法(exgcd)
由裴蜀定理有a*
+b*
=gcd(a,b)且b
+(a mod b)
=gcd(b,a mod b);
则由欧几里得定理知,gcd(a,b)=gcd(b,a mod b);
所以,a
+b
=b
+(a mod b)
= b
+(a-a/b*b)
a
+b
=a
+b(
-a/b
);
然后考虑递推最后一步返回值,这时b=0(上一步a mod b =0)
那么ax=gcd(0,a),则x=1,这时取y=0返回
那么下面就可以愉快的递推了
ll exgcd(ll a,ll &x,ll b,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll d=exgcd(b,x,a%b,y);
ll t=x;
x=y;
y=t-a/b*y;
return d;
}
分析
首先分析题目得到
下面就是exgcd求解并对所求解进行调整
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll exgcd(ll a,ll &x,ll b,ll &y){
if(b==0){
x=1;y=0;
return a;
}
ll d=exgcd(b,x,a%b,y);
ll t=x;
x=y;
y=t-a/b*y;
return d;
}
int x,y,m,n,L;
int main(){
cin>>x>>y>>m>>n>>L;
int mm = m-n , yy = y-x;
ll t,k,p=__gcd(mm,L);
//注意这里p可能是负数
if(p<0)p=-p;
ll m0=mm/p,L0=L/p;
ll r=exgcd(mm,t,L,k);
if(yy%r==0){
t=t*yy/r;
t=(t%L0+L0)%L0;
cout<<t;
}
else cout<<"Impossible";
}
Sum of Consecutive Prime Numbers
首先用欧拉筛筛储出4e7之内的素数,然后使用前缀和求区间和,每次固定右边界,左边界用二分查找判断
#include<bits/stdc++.h>
#define ll long long
#define _for(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 4e7+10;
const int Pri_cnt = 3000000;
int t,prime[Pri_cnt],cnt,n;
ll s[Pri_cnt];
bool st[N];
void inti(){
int p = 1;//表示将要存素数的位置
_for(i,2,4e7){
if(st[i] == 0)prime[p++] = i;
for(int j = 1;j <= p-1 && i*prime[j] <= N;j++){
st[i*prime[j]] = 1;
if(i%prime[j] == 0)break;
}
}
cnt = p-1 ;//表示所存素数的个数
_for(i,1,cnt) s[i]=s[i-1]+prime[i];
}
inline ll f(int l,int r){ return s[r]-s[l]-n; }
int main(){
inti();
cin>>t;
while(t--){
int ans = 0;
cin>>n;
//遍历以i为结尾的连续素数区间
for(int i = 1; i <= cnt && prime[i] <= n; i++){
if(s[i]<n) continue;
int l = 1, r = i, mid, anss=-1;//表示区间[l+1,r]
while(l <= r){
mid = l+r>>1;
if(f(mid-1,i) >= 0){
l = mid+1;
anss = mid;
}
else r = mid-1;
}
if(f(anss-1,i) == 0)ans++;
}
cout<<ans<<endl;
}
return 0;
}
Prime Distance
1. 对给定区间用miller_rabin得到所有素数
2. 遍历判断
#include<bits/stdc++.h>
#define ll long long
#define _for(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
ll qpow(ll x, ll n, ll p) {
ll res = 1;
while(n){
if(n&1)res = res*x%p;
x = x*x%p;
n>>=1;
}
return res;
}
bool query(ll p) {
ll test[10] = {2,3,5,7,11,13,17};
if(p == 1)return 0;
ll t = p-1,k = 0;
while(!(t&1))k++,t>>=1;
for(int i = 0; i<4; i++){
if(p == test[i])return 1;
ll a = qpow(test[i],t,p),nxt = a;
for(int j = 1; j <= k; j++){
nxt = (a*a)%p;
if(nxt == 1 && a != 1 && a != p-1) return 0;
a = nxt;
}
if(a != 1) return 0;
}
return 1;
}
ll prime[1000000],t,l,r;
int main(){
cin>>t;
while(t--){
int cnt = 0;
cin>>l>>r;
for(ll i = l; i <= r; i++)
if(query(i))prime[cnt++] = i;
if(cnt < 2)cout<<"There are no adjacent primes."<<endl;
else {
ll maxn = 0, bl, br, sl, sr, minn = r-l+1;
for(int i = 0; i < cnt-1; i++){
if(prime[i+1]-prime[i]>maxn){
bl=prime[i],br=prime[i+1];
maxn = prime[i+1]-prime[i];
}
if(prime[i+1]-prime[i]<minn){
sl=prime[i],sr=prime[i+1];
minn = prime[i+1]-prime[i];
}
}
cout <<sl<<','<<sr<<" are closest, "
<<bl<<','<<br<<" are most distant."<<endl;
}
}
return 0;
}
Prime Land
1. 欧拉筛预处理出1-30000内的素数
2. 质因子分解
#include<bits/stdc++.h>
#define ll long long
#define _for(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=30000;
int prime[3300], a, b, k, cnt, t, fac[3300], degree[3300];
bool st[N+1];
void inti(){
_for(i,2,N){
if(st[i] == 0)prime[cnt++] = i;
for(int j = 0; j < cnt && prime[j]*i <= N; j++){
st[prime[j]*i] = 1;
if(i%prime[j] == 0)break;
}
}
}
int main(){
inti();
cin>>t;
while(t--){
int n = 1;
memset(degree,0,sizeof degree);
cin>>k;
while(k--){
cin>>a>>b;
while(b--)n*=a;
}
n--;
int p = 0;
_for(i,0,cnt-1){
if(n%prime[i] == 0){
fac[p] = prime[i];
while(n%prime[i] == 0){
n /= prime[i];
degree[p]++;
}
p++;
}
if(n == 1)break;
}
for(int i = p-1; i >= 0; i--)
cout<<fac[i]<<' '<<degree[i]<<' ';
cout<<endl;
}
return 0;
}
X-factor Chains
1. 欧拉筛预处理出1-1000内的素数
2. 对阶乘进行预处理
3. 使用miller_rabin对下述x为大于1000时的素数进行判断
4.
#include<bits/stdc++.h>
#define ll long long
#define _for(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=1000;
int prime[1000], cnt, x; bool st[N+1];
ll factorial[32]={1,1};
void inti(){
_for(i,2,N){
if(st[i] == 0)prime[cnt++] = i;
for(int j = 0; j < cnt && prime[j]*i <= N; j++){
st[prime[j]*i] = 1;
if(i%prime[j] == 0)break;
}
}
for(int i=2;i<32;i++)
factorial[i]=factorial[i-1]*i;
}
ll qpow(ll x,ll n,ll p) {
ll res = 1;
while(n){
if(n & 1)res = res*x%p;
x = x*x%p;
n>>=1;
}
return res;
}
bool query(ll p) {
ll test[10] = {2,3,5,7,11,13,17};
if(p == 1)return 0;
ll t = p-1, k = 0;
while(!(t&1))k++, t>>=1;
for(int i = 0; i < 4; i++){
if(p == test[i])return 1;
ll a = qpow(test[i],t,p), nxt=a;
for(int j=1;j<=k;j++){
nxt = (a*a)%p;
if(nxt == 1 && a != 1 && a != p-1) return 0;
a = nxt;
}
if(a != 1) return 0;
}
return 1;
}
int main(){
inti();
int t; scanf("%d", &t);
while(t--){
scanf("%d", &x);
ll sum = 0, d = 1, pp;
// 得到x的质因子分解
_for(i, 0, cnt-1){
if(query(x)) { sum++; break;}
if(x % prime[i] == 0){
pp = prime[i];
int tem = 0;
while(x % pp == 0){
x /= pp;
tem++;
}
sum += tem;
d *= factorial[tem];
}
if(x == 1)break;
}
printf("%lld %lld\n",sum,factorial[sum]/d);
}
return 0;
}