acm寒假集训第四讲总结
1.有理数取余
思路:
由题意,答案为b在模19260817下的乘法逆元,使用扩展欧几里得算法求出答案,注意x可能为负数的情况即可
代码:
#include <bits/stdc++.h>
#include <tuple>
using namespace std;
inline int getint()
{
int res=0,ch=getchar();
while(!isdigit(ch)&&ch!=EOF){
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+ch-'0';
res%=19260817;
ch=getchar();
}
return res;
}
std::tuple<long long, long long, long long> extendedGCD(long long a, long long b) {
if (b == 0)
return {a, 1, 0};
auto [g, x1, y1] = extendedGCD(b, a % b);
long long x = y1;
long long y = x1 - (a / b) * y1;
return {g, x, y};
}
int main()
{
int a,b;
a=getint();b=getint();
auto [d,x,y]=extendedGCD(b,19260817);
if(d==1)
{
long long inv=(x%19260817+19260817)%19260817;
cout<<(inv*a)%19260817;
}
else
{
cout<<"Angry!";
}
return 0;
}
2.Minimal Coprime
思路:
观察得,每组数据的答案为r-l,由于[l,r]区间中的每个整数k和k+1都构成一个最小互质区间,所以答案就是r-l,注意l和r等于1的情况
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int l,r;
cin>>l>>r;
if(l==1&&r==1)
{
cout<<"1"<<endl;
}
else
{
cout<<(r-l)<<endl;
}
}
return 0;
}
3.素数密度
思路:
使用线性筛筛选出小于等于50000(最大值开根号)的所有素数,在利用这些素数筛出区间内的素数数量即可
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 1000005;
const int N = 50005;
bool a[M], ans[M];
long long cnt = 0, pri[N];
long long L, R;
void prime(int n)
{
for (int i = 2; i <= n; ++i)
if (!a[i])
{
pri[++cnt] = i;
for (int j = i << 1; j <= n; j += i)
a[j] = 1;
}
}
int main()
{
prime(50000);
cin >> L >> R;
L += (L == 1);
if (L > R)
{
cout << "0" << endl;
return 0;
}
memset(ans, 0, sizeof(ans));
for (register int i = 1; i <= cnt && pri[i] * pri[i] <= R; i++)
{
for (long long j = max(2 * 1ll, (L - 1) / pri[i] + 1) * pri[i]; j <= R; j += pri[i])
if (j - L >= 0) ans[j - L] = 1;
}
int tot = 0;
for (int i = 0; i <= R - L; i++)
if (!ans[i]) tot++;
cout << tot << endl;
return 0;
}
4.最大公约数和最小公倍数问题
思路:
由题意,只要计算出y0/x0的所有因子即可,注意相等和相除后不是整数的情况
代码:
#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
int r;
while(b!=0)
{
r=a%b;
a=b;
b=r;
}
return a;
}
int main()
{
int x0,y0,i;
cin>>x0>>y0;
int k=y0/x0;
if(y0%x0!=0)
{
cout<<"0";
return 0;
}
if(x0==y0)
{
cout<<"1";
return 0;
}
int cnt=0;
for(i=1;i<=sqrt(k);i++)
{
if(k%i==0)
{
int a=i;
int b=k/i;
if(gcd(a,b)==1)
{
cnt++;
}
}
}
cnt=cnt*2;
cout<<cnt;
}
学习总结:
通过这次的学习,我学习了数论的一些基本概念,包括gcd的计算,扩展欧几里得算法,线性筛和乘法逆元等,通过解题体会了数学的魅力,通过数学优化算法提高效率
浙公网安备 33010602011771号