Codeforces Round 1016 (Div. 3)
A - Ideal Generator
def solve():
n = int(input())
if n % 2:
print("YES")
else :
print("NO")
t = 1
t = int(input())
for i in range(t):
solve()
B - Expensive Number
最后剩下一个数字肯定能使得数字最小
在此基础上需要使得长度最小的话就可以有前导零
def solve():
s = input()
c0 = 0
ans = 1
for c in s:
if c == '0':
c0 += 1
else:
ans = max(ans, c0 + 1)
ans = len(s) - ans
print(ans)
t = 1
t = int(input())
for i in range(t):
solve()
C - Simple Repetition
1.首先当k>=2的时候除了一个数其他的情况下都不是质数
例如x =2, k =2, 22 = 2 * 11
2.注意11是质数
3.只需要处理k=1的情况下,直接试除法判断质数,注意:1
void solve(){
int x, k;
cin >> x >> k;
int t = x;
if (x == 1 && k == 1){
cout << "NO" << '\n';
return;
}
else if(k == 2 && x == 1){
cout << "YES" << '\n';
return;
}
else if(k > 1){
cout << "NO" << '\n';
return;
}
// cout << x << '\n';
for (int i = 2; i <= x / i; i ++){
if(x % i == 0){
cout << "NO" << '\n';
return;
}
}
cout << "YES" << '\n';
}
D - Skibidi Table
分治
将正方形分成上下左右四个部分,每个部分的做法是相同的
我们可以直接递归求解
注意:贡献
例如你在右下进行递归,别忘了左上的贡献(可以O1计算),模拟即可
LL pw[N];
int get_num(int c, int x, int y){
if(c == 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;
}
//cerr << x << " " << y << '\n';
int res = 0;
int sx = pw[c - 1], sy = pw[c - 1];
if(x <= sx && y <= sy){
res = get_num(c - 1, x, y);
}
if(x <= sx && y > sy){
res = get_num(c - 1, x, y - sy) + pw[(c - 1) * 2] * 3;
}
if(x > sx && y <= sy){
res = get_num(c - 1, x - sx, y) + pw[(c - 1) * 2] * 2;
}
if(x > sx && y > sy){
res = get_num(c - 1, x - sx, y - sy) + pw[(c - 1) * 2] * 1;
}
return res;
}
PII get_xy(int c, int num){
if(c == 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;
if(num == 1) return {1, 1};
if(num == 2) return {2, 2};
if(num == 3) return {2, 1};
if(num == 4) return {1, 2};
}
int t = pw[(c - 1) * 2];
if(num <= t){
PII res = get_xy(c - 1, num);
return res;
}
if(num <= t * 2){
PII res = get_xy(c - 1, num - t);
return {res.x + pw[c - 1], res.y + pw[c - 1]};
}
if(num <= t * 3){
PII res = get_xy(c - 1, num - 2 * t);
return {res.x + pw[c - 1], res.y};
}
if(num <= t * 4){
PII res = get_xy(c - 1, num - 3 * t);
return {res.x, res.y + pw[c - 1]};
}
}
void solve(){
int n , q;
cin >> n >> q;
pw[0] = 1;
for (int i = 1; i <= 60; i ++) pw[i] = pw[i - 1] * 2;
while(q --){
string op;
cin >> op;
if(op == "->"){
int x, y;
cin >> x >> y;
cout << get_num(n, x, y) << '\n';
}
else{
int k;
cin >> k;
PII ans = get_xy(n, k);
cout << ans.x << " " << ans.y << '\n';
}
}
}
E - Min Max MEX
二分答案
check,mex为mid的时候最多能分成段
注意mex答案最多是n + 1, 有很多没有用的部分,可以直接用数组代替map
void solve(){
int n, k;
cin >> n >> k;
std::vector<int> a(n);
map<int, vector<int>> mp;
for (int i = 0; i < n ; i ++){
cin >> a[i];
}
auto check = [&](int mex){
if(mex == 0) return (bool)(1);
vector<int> mp(n * 2 + 1);
queue<int> q;
int t = 0, cnt = 0;
for (auto c : a){
if(c <= n * 2) mp[c] ++, q.push(c);
while(mp[t] > 0 && t < mex) t ++;
if(t >= mex){
t = 0;
while(q.size()){
int u = q.front();
mp[u] = 0;
q.pop();
}
cnt ++;
}
}
return cnt >= k;
};
int l = 0, r = n * 2;
while(l < r){
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l << '\n';
}
F - Hackers and Neural Networks
贪心
取任意一个最大匹配的神经网络,剩下的单独去做
我们可以先取任意一个最大匹配的神经网络,将其都放到a里
剩下m个不同的位置,每一个单独去做给空白填正确数字
int idx, n, m;
map<string, int> mp;
std::vector<int> e[N];
int b[N][N], a[N];
int get(string s){
if(mp.count(s)) return mp[s];
mp[s] = ++ idx;
return idx;
}
void solve(){
mp.clear();
idx = 0;
cin >> n >> m;
for (int i = 1; i <= n; i ++){
string s;
cin >> s;
a[i] = get(s);
e[i].clear();
}
vector<int> c(m + 1), nw(n + 1);
for (int i = 1; i <= m; i ++){
for (int j = 1; j <= n; j ++){
string s;
cin >> s;
int id = get(s);
b[i][j] = id;
if(a[j] == id){
e[j].pb(i);
c[i] ++;
}
}
}
for (int i = 1; i <= n; i ++){
if(e[i].size() == 0){
cout << "-1" << '\n';
return;
}
}
int need = n, ans = 0;
for (int I = 0; I < n; I ++){
if(need == 0) break;
int mid= 0;
for (int i = 1; i <= m; i ++)
if(c[mid] < c[i])
mid = i;
ans += need;
if(need > c[mid]) ans += 2 * (need - c[mid]);
break;
}
cout << ans << '\n';
}
G - Shorten the Array
01-tire
这个异或的题,首先可以联想到trie树
为什么呢
我们可以想枚举右端点r,找出最近的左端点l使得满足条件
这个trie可以实现:
1.建树的过程中,同时维护一下子树的最大id号
2.如何找呢
从高到低枚举二进制位:
当前数字=1, k=1: 我们可以向当前位为0来递归,使得高位前缀和 <= k, 如果不存在直接返回当前贡献
当前位为1的子树不会造成贡献
当前数字=1, k=0: 我们可以向当前位为1来递归,使得高位前缀和 <= k,如果不存在直接返回当前贡献
当前位为0的子树不会造成贡献
当前数字=0, k=1: 我们可以向当前位为1来递归,使得高位前缀和 <= k,如果不存在看另一个子树的贡献之后直接返回当前贡献
当前位为0的子树会使得, 使得高位前缀和 > k,该子树下的所有结点都可以选择,我们直接取id最大的
当前数字=0, k=0: 我们可以向当前位为0来递归,使得高位前缀和 <= k,如果不存在看另一个子树的贡献之后直接返回当前贡献
当前位为1的子树会使得, 使得高位前缀和 > k,该子树下的所有结点都可以选择,我们直接取id最大的
注:高位前缀和指的是我选择走的路线上的值和k对应位异或的和
int n, idx, k;
int a[N];
int trie[N * 35][2], son[N*35];
int mi[N * 35][2];
void insert(int x, int id){
int p = 0;
for (int i = 30; i >= 0; i --){
int u = x >> i & 1;
if(!trie[p][u]) trie[p][u] = ++ idx;
mi[p][u] = max(mi[p][u], id);
p = trie[p][u];
}
son[p] = id;
}
int query(int x){
int p = 0, res = -1;
for (int i = 30; i >= 0; i --){
int u = x >> i & 1;
int v = k >> i & 1;
//cout << i << " " << u << " " << v << " " << x << " " << k << '\n';
if (v == 1){
if (trie[p][u ^ 1]){
p = trie[p][u ^ 1];
}
else return res;
}
if (v == 0){
if (trie[p][u]){
if(trie[p][u ^ 1])
res = max(res, mi[p][u ^ 1]);
p = trie[p][u];
}
else if(trie[p][u ^ 1]) {
res = max(res, mi[p][u ^ 1]);
return res;
}
}
}
res = max(res, son[p]);
return res;
}
void solve(){
idx = 0;
cin >> n >> k;
int ans = 1e9;
for (int i = 0; i <= n * 32; i ++){
trie[i][0] = trie[i][1] = 0;
mi[i][0] = mi[i][1] = 0;
son[i] = 0;
}
for (int i = 1; i <= n; i ++) cin >> a[i];
// insert(a[0], 0);
for (int i = 1; i <= n; i ++){
insert(a[i], i);
int t = query(a[i]);
// cout << i << " " << t << '\n';
if(t != -1)
ans = min(ans, i - t + 1);
}
if(ans == 1e9) ans = -1;
cout << ans << '\n';
}