寒假算法训练第四次总结
第一题
思路:利用扩展欧几里得算法模板求出x,若b与MOD不互质则无解
点击查看代码
#include<iostream>
#include<string>
using namespace std;
typedef long long ll;
const int MOD = 19260817;
//扩展欧几里得算法
ll extended_gcd(ll a, ll b, ll& x, ll& y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
ll gcd = extended_gcd(b, a % b, y, x);
y -= a / b * x;
return gcd;
}
//求b的逆元
ll inv(ll b, ll mod) {
ll x, y;
ll gcd = extended_gcd(b, mod, x, y);
if (gcd != 1) {
return -1;
}
return (x % mod + mod) % mod;
}
//高精度数对低精度数取模
ll mod(const string& num, ll mod) {
ll res = 0;
for (char ch : num) {
res = (res * 10 + (ch - '0')) % mod;
}
return res;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
string a_str, b_str;
cin >> a_str >> b_str;
//取模
ll a = mod(a_str, MOD);
ll b = mod(b_str, MOD);
//求b逆元
ll b_inv = inv(b, MOD);
if (b_inv == -1) {//无解
cout << "Angry!" << endl;
}else{
ll x = (a * b_inv) % MOD;
cout << x << endl;
}
return 0;
}
思路:任意两个连续的数字必互质
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t;
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> t;//测试数据t组
int l, r;
for(int i = 0; i < t; i++) {
cin >> l >> r;
int ans = r-l;
if(l == 1) {
if(r < 2) {
ans++;
}
}
cout << ans << endl;
}
return 0;
}
思路:直接筛一定会超时,必须要转化,可以先预处理出2sqrt(r)区间的素数,因为r的因子最大不超过sqrt(r),最后用这些素数筛掉lr区间的合数即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50000;
int l, r;
int main() {
cin >> l >> r;
if(l == 1) l = 2;
//筛出1~max(sqrt(r))之间所有素数
vector<bool> isPrime(N+1,true);
vector<int> primes;
for(int i = 2; i <= N; i++) {
if(isPrime[i]) {
primes.push_back(i);
}
for(int j = 0; j < primes.size() && i * primes[j] <= N; j++) {
isPrime[i * primes[j]] = false;//标记合数
if(i % primes[j] == 0)
break;
}
}
int len = r - l + 1;
vector<bool> res(len, true);
for(int p : primes) {
if((ll)p * p > r)
break;
ll start;
if(l % p == 0) start = l;
else start = l + (p - l % p);
start = max(start, (ll)p * p);
for(ll j = start; j <= r; j+=p) {
res[j - l] = false;
}
}
int cnt = 0;
for(int i = 0; i < len; i++) {
if(res[i]) cnt++;
}
cout << cnt << endl;
return 0;
}
思路:首先这样的数对的积是固定为x*y,然后直接按照gcd和lcm的定义枚举就行
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll x, y;
int main() {
cin >> x >> y;//x为最大公约数,y为最小公倍数
if(x == y) {
cout << 1 << endl;
return 0;
}
ll xy = x * y;
int cnt = 0;
for(int i = 1; i * x <= sqrt(xy); i++) {
if(xy % (i*x) == 0)
if(__gcd(i*x, xy / (i*x)) == x)
cnt++;
}
cout << 2*cnt << endl;
return 0;
}
思路:先根据数据范围筛掉那些无用数据,然后再统计各个可能的l值对应有多少个元素的倍数可以是l,最后根据结果再次遍历,反推方案
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
const int MAX_M = 1e6+10;
using namespace std;
int n, m;
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >>m;//n个元素,子序列lcm不超过m
vector<int> a(n);
for(int i = 0; i < n; i++) cin >> a[i];
//过滤掉大于m的元素
vector<int> flitered_a;
for(int x : a)
if(x <= m)
flitered_a.push_back(x);
//统计每个元素的频率(利用哈希表)
vector<int> freq(MAX_M, 0);
for(int x : flitered_a)
freq[x]++;
//预处理可能的 LCM 值(只能是某些元素的倍数)
vector<int> lcm_count(MAX_M, 0);
for (int x = 1; x <= m; x++) {
if (freq[x] > 0) { //不存在的元素的倍数不必考虑
for (int multiple = x; multiple <= m; multiple += x) {
lcm_count[multiple] += freq[x];
}
}
}
//找到最大子序列长度和对应的 LCM 值
int max_len = 0;
int best_lcm = 1;
for (int l = 1; l <= m; ++l) {
if (lcm_count[l] > max_len) {
max_len = lcm_count[l];
best_lcm = l;
}
}
//反推出符合要求的元素
vector<int> res;
for(int i = 0; i < n; i++) {
if(a[i] <= m && best_lcm % a[i] == 0) {
res.push_back(i+1);
}
}
//输出结果
cout << best_lcm << ' ' << max_len << endl;
for(int x : res) {
cout << x << ' ';
}
return 0;
}
思路:看学长直播后根据学长提供的思路写的,首先可以明确:2可以生成所有的数,无论奇偶;还有素数无法被生成;生成器必须比生成的数小。因此只有一个素数的话,还有可能合法(以它为生成器的话);但是一旦出现两个素数,就能直接判定数据非法。然后就是先对数组进行从小到大的排序,这样素数的合法出现情况就只能是第一个出现且只出现一次,并且之后所有的数字都可以由该素数表示,如果最小的数字真的是素数的话,之后就是对每个元素进行合法性检查,偶数检查它谁否大于等于该素数的两倍,奇数检查扣掉该奇数的最小质因数后,得到的偶数是否合法。一旦再检测到一个素数就就可以直接判定非法输出
点击查看代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 4e5+9;
int t;
int func(int n) {//求奇数的最小质因数
int res = 2;
while(res++) {
if(n % res == 0) {
break;
}
}
return res;
}
int main(){
cin >> t;
vector<bool> isPrime(N+1,true);
vector<int> primes;
for(int i = 2; i <= N; i++) {
if(isPrime[i]) primes.push_back(i);
for(int j = 0; j < primes.size() && i * primes[j] <= N; j++) {
isPrime[i * primes[j]] = false;
if(i % primes[j] == 0) break;
}
}
while(t--) {
int len; cin >> len;
vector<int> a(len);
for(int i = 0; i < len; i++) cin >> a[i];
sort(a.begin(), a.end());
int pri_cnt = 0;
int ans = 2;
for(int i = 0; i < len; i++) {
//判断素数
if(isPrime[a[i]]) {
pri_cnt++;
if(pri_cnt == 2) {//两个素数就无解
ans = -1;
break;
}
if(pri_cnt == 1 && i != 0) {//素数不在第一个出现也无解
ans = -1;
break;
}
ans = a[i];//暂定答案为该素数
}else{//分别对奇偶数进行合法性判断
if(a[i] % 2 == 0) {//偶数
if(pri_cnt == 0) {//如果这之前还没出现过素数
continue;
}else{//如果出现过素数就判断是否大于等于该素数的两倍
if(a[i] >= 2 * ans) {
continue;
}else{
ans = -1;
break;
}
}
}else{//奇数
if(pri_cnt == 0) {
continue;
}else{
int prime_divider = func(a[i]);
a[i] -= prime_divider;//先将该奇数减去其最小质因子
if(a[i] >= 2 * ans) {//如果得出的偶数能合法
continue;
}else{//得出的偶数非法,无解
ans = -1;
break;
}
}
}
}
}
cout << ans << endl;
}
return 0;
}

浙公网安备 33010602011771号