A. Hossam and Combinatorics
#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;
#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
while(N--){
ll n, maxx = -1, minn = 1e9, minn_num = 0, maxx_num = 0, dif;
cin >> n;
for (int i = 0; i < n; ++i){
int t; cin >> t;
if (maxx < t){maxx = t; maxx_num = 1;}
else if (maxx == t){maxx_num += 1;}
if (minn > t){minn = t; minn_num = 1;}
else if (minn == t){minn_num += 1;}
}
dif = maxx - minn;
if (dif == 0) cout << maxx_num * (maxx_num - 1) << endl;
else cout << maxx_num * minn_num * 2 << endl;
}
}
总结:题目没读懂,一开始理解的题意是:按照给定一个正数,求数组中所有绝对值之差等于这个正数的数量,如果当前数等于这个正数,那么存在另一个相等的数和他相减也符合规则。
后来发现题目要求最大和最小值的difference, 那么只要找到最大和最小值的数量,再分两种情况直接处理就行了。
B. Hossam and Friends
题意:有一个permutation数组,在这个数组中查找所有的区间,满足区间中所有的数都不是数对,数对是输入的有限个数对。
思路:
对于每个元素,如果数对中出现了这个数,那么存储这个元素最小的右边界。然后根据当前元素的最小右边界,对每个元素进行枚举,即可得到结果。枚举时设立L,R指针,R始终指向右边最近的边界,并且不断更新R,直到L为第一个元素。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;
#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
while(N--){
int n, m;
cin >> n >> m;
vi a(n + 1, 1e9);
ll rst = 0;
while (m--){
int t, tt;
cin >> t >> tt;
if (t > tt) swap(t, tt);
a[t] = min(a[t], tt);
}
for (int r = n, l = n; l >= 1; --l){
if (a[l] != 1e9) {r = min(r, a[l] - 1);}
if (l <= r) rst += r - l + 1;
}
cout << rst << endl;
}
}
总结:B题一开始写了个矩阵,并且判断当前元素相邻的下一个元素是否在有序对出现过,后来想了想不对,这样写只能保证相邻的元素没有在数对中,不能保证之前出现的元素没有跟现在的元素组成有序对。
C. Hossam and Trainees
题意:给定一个数组,判定数组中的数是否存在一对数具有公因子x,x>=2。如果是,输出YES。反之NO。
思路:判定数组中两两一组的数是否互质,如果存在一对不互质的数,终止扫描,输出YES。如果扫描结束,输出NO。所以难点在于如何判断两个数是否互质。如果用暴力破解,那么跑test2超时,如果用辗转相除法找最大公约数,test3超时...
12.14 17:06 借鉴他人的思路跟解决方法:
判断两个数是否互质,就看两个数是否有公共质因子。如果在一组数据中,有一个公共质因子出现了至少两次,那么这一组数据中一定有两个数不互质。
题目中最大的数据为1e9,他的最大质因子应该是sqrt(1e9),大概是不超过1e5。所以枚举出1e5以下的所有质数,如果在一组输入中发现某个质因子出现了两次时,就可以直接输出YES。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <unordered_set>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<char> vc;
#define INT_MAX pow(2, 31) - 1
#define INT_MIN -pow(2, 31)
const int N = 1000005;
bool composite_number[N] = {false};
int prime[N], primeSize = 0;
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
const int wc = 1e5;
for (int i = 2; i * i <= wc; ++i){
if (!composite_number[i]){
for (int j = i * i; j <= wc; j += i){composite_number[j] = true;}
}
}
composite_number[1] = true;
for (int i = 2; i <= wc; ++i){
// cout << "i = " << i << endl;
if (!composite_number[i]) prime[primeSize++] = i;
}
//cout << "size = " << primeSize <<endl;
//for (int i = 0; i < primeSize; ++i){cout << prime[i] << endl;}
int _;
cin >> _;
while (_--){
int n, tag = 0;
cin >> n;
set<int> sett;
vi nums(n);
for (int i = 0; i < n; ++i) cin >> nums[i];
for (int i = 0; i < n && !tag ; ++i){
for (int j = 0; prime[j] * prime[j] <= nums[i]; ++j){
int p = prime[j];
if (nums[i] % p == 0){
if (sett.count(p)) {tag = 1; break;}
sett.insert(p);
while (nums[i] % p == 0){nums[i] /= p;}
}
}
if (nums[i] > 1){
if (sett.count(nums[i])) {tag = 1; break;}
sett.insert(nums[i]);
}
}
cout << (tag == 1 ? "YES" : "NO") << endl;
}
return 0;
}
总结,由于每输入一个数都可以检查是否有重复的因子,所以不需要建立数组存储输入,只需要将每次输入的因子存储起来即可。