比赛链接:
Codeforces Round #837 (Div. 2)
A. Hossam and Combinatorics
题目描述
t组数据,每组数据有n个数,问有多少数对的极差的绝对值等于这n个数中最大的极差的绝对值。
例如
6
7 2 8 3 2 10
极差为10
答案为4
有(2, 10), (2, 10), (10, 2), (10, 2)四个数对(2为上面两个下标不同的2)
思路
有两种情况,一种情况为所有数全部相等吗,即极差为0。另一种是存在不同的最小数和最大数,即极差不为0。
极差为0的情况,n个数中的任意一个数都可以和剩下的n-1个数配对,答案为n*(n-1)
极差不为0的情况,任意一个最小数都可以和所有最大数匹配,任意一个最大数也可以和所有的最小数匹配,答案为2 * mp[min(a[i])] * mp[max(a[i])]
代码
#include <bits/stdc++.h>
#define up(i, j, n, k) for (int i = j; i <= n; i += k)
#define dw(i, j, n, k) for (int i = j; i >= n; i -= k)
#define LL long long
using namespace std;
const int mod = 1e9 + 7;
const int mn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
typedef pair<int, int> PII;
int t;
void solve() {
LL n, mi = INF, mx = -INF;
cin >> n;
vector<LL> a(n + 1);
map<LL, LL> mp;
up(i, 1, n, 1) {
cin >> a[i];
mp[a[i]]++;
mi = min(mi, a[i]);
mx = max(mx, a[i]);
}
if (mi == mx) {
cout << n * (n - 1) << "\n";
return ;
}
cout << 2 * mp[mi] * mp[mx] << "\n";
}
int main() {
// ios ::sync_with_stdio(false);
// t = 1;
cin >> t;
while (t--) solve();
}
B. Hossam and Friends
题目描述
定义满足[i, i+1, i+2…j](1 \le i \le j \le n)为好区间,总共有1~n个数,有m对数不可以同时出现,问共计有多少好区间
例如
4 2 (n和m)
1 2
2 3
有1,2,3,4个数
1,2不可以同时出现
2,3不可以同时出现
那么满足好区间的区间有[1],[2],[3],[4],[3,4];
[1,2],[1,2,3],[1,2,3,4],[2,3],[2,3,4]都因为1,2或者2,3同时出现而不满足
思路
如果1,2 不能同时出现,那么1,3和1,4直到1,n都不能同时出现,所以在所有不可以同时出现的数对(x,y)中,对于所有x相同的数对,只需要记录最小的y即可。
当n=10时,如果(3, 5)不可以同时出现,那么1到5,1到6…都不可以出现,所以还需要预处理下如果第i个数可以到达的右端点远于i+1, i+2 ... n中任意一个数可以到达的右端点,那么将这第i个数可以到达的右端点更新为 i+1, i+2 ... n中可到达的右端点最小的点。我们可以从后向前更新,这样可以做到O(n)的更新。f[i] = min(f[i],f[i+1]) [i从n-1到1]
现在我们得到了所有可行的区间,那么如何不重复计算这些区间所有的子区间的数量呢?
如果采用\frac{n*(n-1)}{2}这个公式的话会计算出很多重复的区间,我们可以换个思路想,对于每个左端点只加上这个左端点可达的所有区间,例如区间[1,3]。可达的区间为[1],[1,2],[1,2,3],由于左端点的不同,可以保证不会有重复。ans += f[i] - i + 1 (f[i]存储的是i可达的右端点)
由于读入的右端点是不可达的,所有存储的时候右端点-1才是可以最远可以到达的点。
代码
#include <bits/stdc++.h>
#define up(i, j, n, k) for (int i = j; i <= n; i += k)
#define dw(i, j, n, k) for (int i = j; i >= n; i -= k)
#define LL long long
#define midlr (l + r) >> 1
#define rson k << 1 | 1
#define lson k << 1
using namespace std;
typedef pair<int, int> PII;
const int mod = 998244353;
const int mn = 2e6 + 10;
const int INF = 0x3f3f3f3f;
LL n, m, a[mn], f[mn];
void solve() {
cin >> n >> m;
up(i, 1, n, 1) f[i] = n;
LL ans = 0;
up(i, 1, m, 1) {
LL x, y;
cin >> x >> y;
if (x > y) swap(x, y);
f[x] = min(f[x], y - 1);
}
dw(i, n - 1, 1, 1)
if (f[i] > f[i + 1])
f[i] = f[i + 1];
up(i, 1, n, 1)
ans += f[i] - i + 1;
cout << ans << "\n";
}
int main() {
int t;
ios ::sync_with_stdio(false);
cin >> t;
while (t--) {
solve();
}
return 0;
}
C. Hossam and Trainees
题目描述
n个数,问存不存在两个数是不互质的。数的范围1 \le a_i \le 10^9
例如
2 (t)
3 (n)
32 48 7 (n个数)
3
14 5 9
YES 32和48不互质
NO 所有数都是互质的
思路
质因数分解板子题,由于10^9最大的因数也不会超过\sqrt{10^9},所以用欧拉筛绰绰有余。
对于每个a_i,我们都对其进行质因数分解,如果分解质因数后发现该因子再之前已经出现过mp[p[i]] != 0那么说明这个数与之前的某个数有共同的因子,所以直接输出yes即可
同时不要忘记存储质因数分解后剩下的x,如果x>1说明x本身也是个质数,需要存储起来
例如10000007和20000014,不存储x的话就会WA
代码
#include <bits/stdc++.h>
#define up(i, j, n, k) for (int i = j; i <= n; i += k)
#define dw(i, j, n, k) for (int i = j; i >= n; i -= k)
#define LL long long
#define midlr (l + r) >> 1
#define rson k << 1 | 1
#define lson k << 1
using namespace std;
typedef pair<int, int> PII;
const int mod = 998244353;
const int mn = 2e6 + 10;
const int INF = 0x3f3f3f3f;
LL n, m, a[mn];
LL p[mn], cnt;
bool v[mn];
bool judge_prime(int n) {
if (n == 1) return false;
if (n == 2 || n == 3) return true;
if ((n % 6 != 5) && (n % 6 != 1)) return false;
for (int i = 5; i <= n / i; i += 6)
if ((n % i == 0) || (n % (i + 2) == 0)) return false;
return true;
}
void solve() {
cin >> n;
map<LL, LL> mp, zz;
int one = 0;
up(j, 1, n, 1) cin >> a[j];
up(j, 1, n, 1) {
LL x = a[j];
for (int i = 1; i <= cnt; i++) {
if (p[i] * p[i] > x) break;
if (x % p[i] == 0) {
if (mp[p[i]]) {
cout << "Yes\n";
return;
}
while (x % p[i] == 0)
x /= p[i];
mp[p[i]] = 1;
}
}
if (x > 1) {
if (mp[x]) {
cout << "Yes\n";
return;
}
mp[x] = 1;
}
}
cout << "No\n";
}
int main() {
int t;
ios ::sync_with_stdio(false);
is_prime(100000);
cin >> t;
while (t--) {
solve();
}
return 0;
}