Codeforces Round 1016 (Div. 3)
A. Ideal Generator
AC code:
void solve() {
int n; cin >> n;
if (n % 2) cout << "YES" << endl;
else cout << "NO" << endl;
}
B. Expensive Number
思路:
只要最小化分母元素即可,即删到只剩一位,成本必然为1;
显然要使得操作数最小,后缀0全部都要删除,再删除前缀中的所有非0数字,留一个即可
AC code:
void solve() {
string s; cin >> s;
if (s.size() == 1) {
cout << 0 << endl;
return;
}
int cnt = 0;
bool flag = false;
for (int i = s.size() - 1; i >= 0; i --) {
if (s[i] == '0') {
if (!flag) cnt ++;
} else {
flag = true;
cnt ++;
}
}
cout << cnt-1 << endl;
}
C. Simple Repetition
题意:
给出数字n,数字n首尾相接k次组成“nnnnnn”,判断相接后的数字是否为素数
思路:
打表,发现只要k>1就一定是非素数,否则单独判断一下n是否为素数即可
是这样吗
实际上n=1是特殊的,对于1的不同相接元素是存在素数的,比如11
AC code:
iprime(int x) {
if (x == 1) return false;
for (int i = 2; i <= x / i; i ++) {
if (x % i == 0) return false;
} return true;
}
void solve() {
int n; cin >> n;
string s = to_string(n);
int k; cin >> k;
if (n == 1) {
int ca = 0;
for (int i = 0; i < k; i ++) {
ca += (LL)pow(10, i);
}
if (iprime(ca)) cout << "Yes" << endl;
else cout << "No" << endl;
return;
}
if (k > 1) {
cout << "No" << endl;
return;
}else if (k == 1) {
if (iprime(n)) cout << "Yes" << endl;
else cout << "No" << endl;
return;
}
}
D. Skibidi Table
题意:
ε=(´ο`*)))唉,被递归模拟创思了。
思路:
首先我们来看如何通过一个坐标来寻找到其位置的元素:
-
我们可以将整个图看做多个由四个元素的方块叠成的,事实上也是这样的
图的大小为 2 n ∗ 2 n 2^n*2^n 2n∗2n ,现在尝试将其四等分,那么每一块的最大元素为:
左上 2 2 n − 2 , 右下 2 2 n − 2 ∗ 2 , 左下 2 2 n − 2 ∗ 3 , 右上 2 2 n − 2 ∗ 4 左上2^{2n- 2}, 右下2^{2n-2}*2, 左下2^{2n-2}*3, 右上2^{2n-2}*4 左上22n−2,右下22n−2∗2,左下22n−2∗3,右上22n−2∗4
划分四块的mid值为 2 n − 1 2^{n - 1} 2n−1
以此为条件,我们可以不断将当前需要寻找的{x,y}不断向左上角的{1,2,3,4}进行递归
在递归过程中,四块元素都需要添加不同的值,例如左下元素是 2 2 n − 1 2^{2n-1} 22n−1+1开始的,则在递归到左下时需要额外添加 2 2 n − 1 2^{2n-1} 22n−1
当n==1时,我们即可return找到的值
-
同理,对于寻找大小为x的值的坐标
我们的思路还是递归到最左上的{1,2,3,4},但有一点需要注意
在递归求取{x,y}推x时,我们将坐标不断减少mid值来向初试四方块靠近
但在x求取{x,y}时,由于我们的真实坐标是需要由最终推出的四元素坐标增加不同值得到的,所以递归过程中,
一直这削减的是所求元素x的大小去向{1,2,3,4}靠近,而记录的坐标值是不断增加的
AC code:
int getd(int x, int y, int n) {
if (n == 1) {
if (x == 1 && y == 1) return 1;
if (x == 1 && y == 2) return 4;
if (x == 2 && y == 1) return 3;
if (x == 2 && y == 2) return 2;
}
int mid = (1LL << n) / 2;
if (x <= mid && y <= mid) return getd(x, y, n - 1);
else if (x <= mid && y > mid) return getd(x, y - mid, n - 1) + (1LL << (2*n-2))*3;
else if (x > mid && y <= mid) return getd(x - mid, y, n - 1) + (1LL << (2*n-2))*2;
//else if (x >= mid && y >= mid)
return getd(x - mid, y - mid, n - 1) + (1LL << (2*n-2));
}
PII loc(int pos, int n) {
if (n == 1) {
if (pos == 1) return {1, 1};
if (pos == 2) return {2, 2};
if (pos == 3) return {2, 1};
if (pos == 4) return {1, 2};
}
int mid = (1LL << n) / 2;
int t = (1LL << (2*n - 2));
if (pos >= 1 && pos <= t) {
return loc(pos, n - 1);
}
else if (pos >= t + 1 && pos <= t*2) {
auto [x, y] = loc(pos - t, n - 1);
return {x + mid, y + mid};
}
else if (pos >= t*2+1 && pos <= t*3) {
auto [x, y] = loc(pos - 2*t, n - 1);
return {x + mid, y};
}
//else (pos >= t*3+1 && pos <= t*4) {
auto [x, y] = loc((pos - 3*t), n - 1);
return {x, y + mid};
}
void solve() {
int n, q;
cin >> n;
cin >> q;
while (q --) {
string s; cin >> s;
if (s[0] == '-') {
int x, y; cin >> x >> y;
cout << getd(x, y, n) << endl;
} else {
int pos; cin >> pos;
auto [x, y] = loc(pos, n);
cout << x << ' ' << y << endl;
}
}
}
E. Min Max MEX
思路:
很典的二分,直接二分Mex的值,然后尽可能的分成k段
主要问题在check条件中记录Mex的过程中选择的方法,用set,umap的全被创思了
这里其实用一个普通数组即可实现了
int n, k;
int a[N];
bool check(int x) {
int cnt = 0;
int now = 0;
vector<int> pos(x + 1, 0);
for (int i = 1; i <= n; i ++) {
if (a[i] < x && !pos[a[i]]) {
now ++;
pos[a[i]] = 1;
}
if (now >= x) {
cnt ++;
now = 0;
for (int j = 0; j <= x; j ++) pos[j] = 0;
}
}
return cnt >= k;
}
void solve() {
cin >> n >> k;
for (int i = 1; i <= n; i ++) cin >> a[i];
int l = 0, r = n, ans = 0;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
}