Codeforces Round 864 (Div. 2)(A~D)

A. Li Hua and Maze

 给出两个不相邻的点,最少需要堵上几个方格,才能使得两个方格之间不能互相到达。

思路:显然,对于不邻任何边界的方格来说,最少需要的是4,即上下左右都堵上;邻一个边界就-1,两个方格取一下最小值即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 2e5 + 5;
int t, n, m, x1, y1, x2, y2;

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin >> t;
	while(t --) {
		std::cin >> n >> m;
		std::cin >> x1 >> y1 >> x2 >> y2;
		int ans1 = 4, ans2 = 4;
		if(x1 == 1 || x1 == n) ans1 --;
		if(y1 == 1 || y1 == m) ans1 --;
		if(x2 == 1 || x2 == n) ans2 --;
		if(y2 == 1 || y2 == m) ans2 --;
		std::cout << std::min(ans1, ans2) << '\n';
	}
	return 0;
}

B. Li Hua and Pattern

给出一个n*n的矩阵,操作k次,判断能否使得当前矩形和旋转180°后的图形完全相同。每次操作是将格子的颜色翻转。

思路:显然,将格子分为四部分,对角的两两都应该中心对称。对于两两方格的两个坐标有相加等于n+1的关系,判断一下即可。注意,对于奇数时的中心那一条,应该等于同一条线上的另一部分。对于操作次数k,如果小于不同的方格数,则一定不满足条件;若是大于k,n是偶数时,k-cnt必须是偶数。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e3 + 5;
int t, n, k;
int a[N][N];

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin >> t;
	while(t --) {
		std::cin >> n >> k;
		for(int i = 1; i <= n; i ++) {
			for(int j = 1; j <= n; j ++) {
				std::cin >> a[i][j];
			}
		}
		int m = (n + 1) / 2;
		int cnt = 0;
		for(int i = 1; i <= m; i ++) {
			for(int j = 1; j <= m; j ++) {
				if(a[i][j] != a[1 + n - i][1 + n - j])
					cnt ++;
			}
		}
		for(int i = m + 1; i <= n; i ++) {
			for(int j = 1; j <= n / 2; j ++) {
				if(a[i][j] != a[1 + n - i][1 + n - j])
					cnt ++;
			}
		}
		if(k < cnt || (k - cnt) % 2 && n % 2 == 0)
			std::cout << "NO" << '\n';
		else
			std::cout << "YES" << '\n';
	}
	return 0;
}

C. Li Hua and Chess

 在n*m的方格中猜一个确定位置。每次可以询问目标位置和询问位置的距离,注意,距离是指经过八个方向移动的最小距离,在三次询问之内找到答案。

思路:观察移动方式,我们可以发现对于一个位置来说,向外扩展x圈上的点到中心点的距离都是x。那么我们可以先询问(1, 1)点,然后再问(1 + len, 1 + len)点,当然,注意和边界的判断。那么答案位置必然在第二次询问的点的正上方或者正左方。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e3 + 5;
int t, n, m;

int ask(int x, int y) {
	std::cout << "? " << x << ' ' << y << '\n';
	std::cout.flush();
	int dis;
	std::cin >> dis;
	return dis;
}

void work() {
	int a = 1, b = 1;
	int len = ask(a, b);
	if(!len) {
		std::cout << "! " << a << ' ' << b << '\n';
		return;
	}
	a = std::min(a + len, n), b = std::min(b + len, m);
	len = ask(a, b);
	if(!len) {
		std::cout << "! " << a << ' ' << b << '\n';
		return;
	}
	if(len >= a && len < b) {
		std::cout << "! " << a << ' ' << b - len << '\n';
		return;
	}
	else if(len >= b && len < a) {
		std::cout << "! " << a - len << ' ' << b << '\n';
		return;
	}
	int aa = a, bb = b, ll = len;
	a -= len;
	len = ask(a, b);
	if(!len) {
		std::cout << "! " << a << ' ' << b << '\n';
		return;
	}
	std::cout << "! " << aa << ' ' << bb - ll << '\n';
}

int main() {
	// std::ios::sync_with_stdio(false);
	// std::cin.tie(0);
	// std::cout.tie(0);
	std::cin >> t;
	while(t --) {
		std::cin >> n >> m;
		work();
		std::cout.flush();
	}
	return 0;
}

 D. Li Hua and Tree

给出一棵树,进行k次操作,操作1是计算x的子树权值的和,操作2是交换x和x的重子,即断开x和x的父节点之间的边,链接x的重子和x的父节点之间的边。定义重子是x中具有最大子树的子节点,若有多个点满足条件,则重子是索引最小的那个点。

思路:模拟整个过程即可,注意细节。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define int long long
const int N = 1e5 + 5;
int n, m;
std::vector<int> vec[N];
int a[N], w[N], fa[N], val[N];

struct node{
    int w, id;
    bool operator<(const node &a) const{
        if (w != a.w) return w > a.w;
        return id < a.id;
    }
};
std::set<node> s[N];

void DFS(int u, int f){
    val[u] = a[u];
    w[u] = 1;
    for(auto v : vec[u]){
        if (v == f) continue;
        fa[v] = u;
        DFS(v, u);
        val[u] += val[v];
        w[u] += w[v];
        s[u].insert({w[v], v});
    }
}

signed main(){
    std::cin.tie(0);
    std::cout.tie(0);
    std::ios::sync_with_stdio(0);
    std::cin >> n >> m;
    for(int i = 1; i <= n; i ++) {
    	std::cin >> a[i];
    }
    for(int i = 1; i < n; i ++) {
        int u, v;
        std::cin >> u >> v;
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    DFS(1, -1);
    while(m --){
        int op, x;
        std::cin >> op >> x;
        if(op == 1) 
        	std::cout << val[x] << '\n';
        else {
            if (s[x].empty()) continue;
            int son = s[x].begin() -> id;
            s[fa[x]].erase({w[x], x});
            s[x].erase(s[x].begin());
            int big = w[son];
            int value = val[son];
            w[son] = w[x];
            w[x] -= big;
            val[son] = val[x];
            val[x] -= value;
            s[fa[x]].insert({w[son], son});
            s[son].insert({w[x], x});
            fa[son] = fa[x];
            fa[x] = son;
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值