FZU 寒假ACM第四讲

1.有理数取余

 p=19260817,显然p是一个质数

设x\equiva/b(mod p),t=a/b mod p=x mod p

可以得到两个方程

a/b=k1*p+t 也即 a=k1*b*p+b*t

x=k2*p+t 也即 b*x=k2*b*p+b*t

相减得a=b*x+k*p

由裴蜀定理可得,如果a和b是不全为0的整数,并且ax+by=c有解,那么c一定是gcd(a,b)的整数倍

所以a=b*x+k*p有解当且仅当gcd(b,p)|a,若a%gcd(b,p)!=0直接输出Angry!

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define p 19260817
long long a,b,d,y,x,k;
long long read() {
	long long ans=0;
	char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') ans=(ans*10+c-'0')%p,c=getchar();
	return ans;
}
long long exgcd(long long a,long long b)
{
	if(b==0)
	{
		x=1;
		y=0;
		return a;
	}
	long long d=exgcd(b,a%b);
	long long z=x;
	x=y;
	y=z-y*(a/b);
	return d;
}
int main()
{
	a=read();
	b=read();
	d=exgcd(b,p);
	if(a%d!=0)printf("Angry!");
	else printf("%lld",((x*a/d%p)+p)%p);
} 

2.Minimal Coprime

题目理解:我们需要找到在区间 [l, r] 中所有的最小互质区间的数量。一个区间 [a, b] 是互质的,当且仅当 a 和 b 互质(即 gcd(a, b) = 1)。一个互质区间是最小的,当且仅当它不包含任何其他互质区间(除了它自己)。

性质:如果 [a, b] 是最小互质区间,那么 a 和 b 必须互质,对于任何 a<c<b,区间 [a,c] 或 [c, b] 都不能是互质的,否则 [a, b] 就不是最小的。

最小的互质区间只能是长度为 2 的区间 [a, a+1],其中 a 和 a+1 互质。

因为如果区间长度大于2,比如 [a,a+2],那么 [a,a+1] 或 [a+1,a+2] 可能是互质的,导致 [a, a+2] 不是最小的。

结论:最小互质区间的数量等于区间 [l,r] 中满足 gcd(a,a+1)=1 的 a 的数量

因为 a 和 a+1 总是互质的(它们的最大公约数是 1),所以所有长度为 2 的区间 [a, a+1] 都是最小互质区间

特判 [1, 1]

当 l = r = 1 时,区间 [1, 1] 是一个最小互质区间,数量为 1

代码如下:

#include<iostream>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        long long l,r;
        cin>>l>>r;
        if (l==r){
            if(l==1)
			{
                cout<<1<<endl;
            }
			else
			{
                cout<<0<<endl;
            }
        }
		else 
		{
            cout<<r-l<<endl;
        }
    }
    return 0;
}

3.素数密度

  1. 预处理小素数:首先生成所有小于等于 sqrt(R) 的素数。这些素数将用于后续的筛选过程。

  2. 区间筛选:使用预处理得到的小素数来标记区间 [L, R] 内的合数。对于每个小素数 p,找到其在区间中的第一个倍数,并标记所有后续的倍数。

  3. 处理特殊情况:处理数值 1 的特殊情况,因为 1 不是素数

代码思路

  1. 预处理小素数

    • 使用埃拉托斯特尼筛法生成所有小于等于 sqrt(R) 的素数。

    • 将这些素数存储在 primes 向量中。

  2. 区间筛法

    • 初始化一个布尔数组 marked,表示区间 [L, R] 内的每个数是否为素数。

    • 对于每个小素数 p,找到其在区间中的第一个倍数(大于等于 L),并标记所有后续的倍数为合数。

  3. 处理特殊情况

    • 如果区间包含 1,将其标记为非素数。

  4. 统计结果

    • 遍历 marked 数组,统计其中为 true 的个数,即为区间内的素数个数。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int countPrimes(long long L, long long R){
    if(R<2)return 0;
    int sqrtR=sqrt(R)+1;
    vector<bool>sieve(sqrtR+1,true);
    sieve[0]=sieve[1]=false;
    for(int i=2;i*i<=sqrtR;++i){
        if(sieve[i]){
            for(int j=i*i;j<=sqrtR;j+=i){
                sieve[j]=false;
            }
        }
    }
    vector<int>primes;
    for (int i=2;i<=sqrtR;++i){
        if(sieve[i]){
            primes.push_back(i);
        }
    }
    vector<bool>marked(R-L+1,true);
    for (int p:primes){
        long long start=max((long long)p*p,L+((p-L%p)%p));
        if(start>R)continue;
        for(long long j=start;j<=R;j+=p){
            marked[j-L]=false;
        }
    }
    if(L<=1){
        marked[1-L]=false;
    }
    int count=0;
    for (bool isPrime:marked){
        if(isPrime){
            count++;
        }
    }
    return count;
}
int main(){
    long long L,R;
    cin>>L>>R;
    cout<<countPrimes(L,R)<<endl;
}

4.最大公约数和最小公倍数问题

此题代码和思路来源于洛谷P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题 - 洛谷

核心思路:先将两数相乘,遍历它的因子

理论支撑:最大公约数和最小公倍数的乘积就是原两个数的积,辗转相除法求最大公约数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int m,n,ans,flag;
ll gcd(ll x,ll y)
{
    if(y==0)
	{
		return x;
	}
    return gcd(y,x%y);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=sqrt(1ll*m*n);i++)
    {
        if((1ll*n*m)%i==0&&gcd(i,(1ll*n*m)/i)==n)
        {
            ans++;
            if(1ll*i*i==1ll*n*m)flag=1;
        }
    }
    cout<<ans*2-flag;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值