Codeforces Round 1016 (Div. 3) A-G

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';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值