Codeforces Round #808 (Div. 2) A-D
Codeforces Round #808 (Div. 2)
https://codeforces.com/contest/1708
被虐惨了(爆哭...
A. Difference Operations
题意
对于任意一个 \(2\leq i\leq n\),可以把 \(a_i\) 变成\(a_{i-1}\),求能否经过若干操作,使得 \(a_i=0,2\leq i\leq n\)
分析
上述操作暗含一种"传递"的思想,即可以从第一项传递到后面。所以能否变为全0就看 是否所有的数都为a[1]的倍数
十分不严谨的证明:
若存在 \(a_k\),不为 \(a_1\) 的倍数,而\(a_1,a_2,...,a_{k-1}\) 皆为 \(a_1\) 的倍数,那么这些数必然能最终转化为0,最后只剩一个 \(a_k\) 没法消掉。
故所有数都要是 \(a_1\) 的倍数才行
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N], n;
void solve () {
int n;
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 2; i <= n; i ++) {
if (a[i] % a[1]) {
cout << "NO\n";
return ;
}
}
cout << "YES\n";
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//都能整除1就ok
B. Difference of GCDs
题意
给定区间 \([l,r]\),试构造n项数列 \(a_i,(l\leq a_i\leq r)\),使得每一项 \(gcd(i,a_i)\) 都不同
分析
第一想法是构造 i 的倍数,因为每一个 i 是不同的,按照其倍数来构造就能够使得 gcd 在每一项都不同
关于如何找倍数:
暴力找是会超时的,所以我们就要用到————
结论:区间 \([l,r]\) 内 x 的最小倍数为 \(\lceil \frac lx \rceil \times x\),然后再判断该数字是否在区间内即可
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N];
void solve () {
int n, l, r;
cin >> n >> l >> r;
vector <int> v;
for (int i = 1; i <= n; i ++) {
bool suc = false;
int x = (int)ceil(1.0*l/i)*i;
if (x >= l && x <= r) {
v.push_back (x);
}
else {
cout << "NO\n";
return ;
}
}
cout << "YES\n";
for (auto i : v) cout << i << ' ';
cout << endl;
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//gcd(i, ai)全不同
//构造i的倍数即可
C. Doremy's IQ
题意
现有智商q 和 n 个难度的问题,对于任意难度值为 \(a_i\) 的问题:
可以选择挑战(必须保证此时 q > 0)或不挑战
- 选择挑战 \(a_i>q\),的问题则会消耗一点 q
- 选择挑战 \(a_i\leq q\),的问题则 q 不变
分析
贪心:对于不能取的,如果不影响后面一整段的选取,那么可以拿走
因为对于需要 q-- 的选取,无论如何都要减少,那么放在后面一定更优 (对于后续影响更少)
所以预处理每一个点取掉所需的 q 值即可
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, q;
int a[N], s[N];//难度 所需q
void solve () {
cin >> n >> q;
vector <int> b(n+1, 0);
for (int i = 1; i <= n; i ++)
cin >> a[i];
s[n] = 1;
//预处理需求
for (int i = n - 1; i >= 1; i --) {
if (a[i] <= s[i+1]) s[i] = s[i+1];
else s[i] = s[i+1] + 1;
}
for (int i = 1; i <= n; i ++) {
if (q >= s[i]) {
for (int j = i; j <= n; j ++)
b[j] = 1; //后面一整段都选
break;
}
if (q >= a[i]) b[i] = 1;
}
for (int i = 1; i <= n; i ++)
cout << b[i];
cout << endl;
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
//贪心
//优先取了不用--的
//1后面添0,不够了再往前凑
//记录最末尾的1
//对于不能取的,如果不影响后面一整段的选取,那么可以拿走
D. Difference Array
题意
对于一个(已经从小到大排好序的)序列a, 每次都求其相邻两项之差,然后再从小到大排序 ... 如此反复 n-1 次,求最后剩下的数是多少
分析
这样的操作下,数列减的速度是非常快的,也就是说,易出现很多的0,0的操作没啥意义,所以我们要找到第一个 >0 的数对其后的序列进行排序,就能大大减少复杂度
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int a[N], n;
void solve () {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
//priority_queue <int, vector<int>, greater<int>> q, p;
int pos;
for (int i = 1; i <= n; i ++) {
if (a[i]) {
pos = i - 1;
break;
}
}
while (n > 1) {
for (int i = max(1, pos); i < n; i ++)
a[i] = a[i+1] - a[i];
n --;
sort (a + pos, a + n + 1);
pos = upper_bound (a + 1, a + n + 1, 0) - (a + 1);
//pos --;
if (pos == n - 1) break;
}
cout << a[n] << endl;
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//二分