VP Codeforces Round 896 (Div. 2)


A. Make It Zero

题意:给你一个数组,每次操作一个区间,让这个区间的数都变成区间的异或和,操作不能超过8次,使得数组全变成0。

如果数组是偶数,直接操作两次[1,n]就行了。
如果数组是奇数,也是先操作一下[1,n],这时数组都变成了一样的数,然后操作[1,n1],前n1个就变成0了,然后操作两次[n1,n]就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::vector<std::pair<int, int>> ans;
    ans.push_back({1, n});
    if (n & 1) {
    	ans.push_back({1, n - 1});
    	ans.push_back({n - 1, n});
    	ans.push_back({n - 1, n});
    } else {
    	ans.push_back({1, n});
    }

    std::cout << ans.size() << "\n";
    for (auto & [l, r] : ans) {
    	std::cout << l << " " << r << "\n";
    }
}

B. 2D Traveling

题意:有n个坐标,前k个坐标之间可以不费代价的任意行走。如果两个坐标中一个不是前k个,那么代价就是曼哈顿距离。求ab的最小代价。

两个点直接到达肯定是最短的,经过中间一个点再取终点肯定不优。但现在前k个点可以互相到达,那么可以选一个到a最短的点和到b最短的点,因为这两个点之间不消耗代价,可能更优。

点击查看代码
void solve() {
    int n, k, a, b;
    std::cin >> n >> k >> a >> b;
    -- a, -- b;
    std::vector<i64> x(n), y(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> x[i] >> y[i];
    }

    if (a > b) {
    	std::swap(a, b);
    }

    if (a < k && b < k) {
    	std::cout << 0 << "\n";
    } else {
    	i64 mina = 1e18, minb = 1e18;
    	for (int i = 0; i < k; ++ i) {
    		mina = std::min(mina, std::abs(x[i] - x[a]) + std::abs(y[i] - y[a]));
    		minb = std::min(minb, std::abs(x[i] - x[b]) + std::abs(y[i] - y[b]));
    	}

    	if (a < k) {
    		mina = 0;
    	}

    	i64 ans = std::min(mina + minb, std::abs(x[a] - x[b]) + std::abs(y[a] - y[b]));
    	std::cout << ans << "\n";
    } 
}

C. Fill in the Matrix

题意:构造一个n×m的数组,使得每一行都是[0,n1]的排列,然后vj代表第j列的mex,总价值就是所有vjmex。求一个方案使得最终mex最大。

赛时手玩了一下就懂了。
0 1 2 3 4 5
5 0 1 2 3 4
4 5 0 1 2 3
3 4 5 0 1 2
2 3 4 5 0 1
0 1 2 3 4 5
就是从(i,i)开始放0循环到(i,i1)依次放数。放到m1行就行了,发现前m1行就凑出了mex最大。剩下的行跟第一行一样就行了。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;

    std::vector a(n, std::vector<int>(m));
    for (int i = 0; i < n; ++ i) {
    	if (i >= m - 1) {
    		for (int j = 0; j < m; ++ j) {
    			a[i][j] = j;
    		}
    		continue;
    	}
    	int x = 0;
    	for (int j = i; j < m; ++ j) {
    		a[i][j] = x ++ ;
    	}

    	for (int j = 0; j < i; ++ j) {
    		a[i][j] = x ++ ;
    	}
    }

    int ans = 0;
    std::set<int> row;
    for (int j = 0; j < m; ++ j) {
    	std::set<int> col;
    	int mex = 0;
    	for (int i = 0; i < n; ++ i) {
    		col.insert(a[i][j]);
    		while (col.count(mex)) {
    			++ mex;
    		}
    	}
    	// std::cout << mex << "\n";

    	row.insert(mex);
    	while (row.count(ans)) {
    		++ ans;
    	}
    }

    std::cout << ans << "\n";
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		std::cout << a[i][j] << " \n"[j == m - 1];
    	}
    }
}

D1. Candy Party (Easy Version)

题意:n个人每个人有一个糖果。每个人必须恰好给一个人2的幂的糖果,并且恰好被一个人给糖果。要使得最终每个人的糖果数相等。

每个人要给出的糖果和接受的糖果数是固定的,记录下来看给出的和收入的2的幂的数量是不是一样。注意特判有一个人不过怎么凑的凑不出平均数的情况。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<i64> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    i64 sum = std::accumulate(a.begin(), a.end(), 0ll);
    if (sum % n) {
    	std::cout << "NO\n";
    	return;
    }

    i64 x = sum / n;
    std::vector<int> cnt1(30), cnt2(30);
    for (int i = 0; i < n; ++ i) {
    	if (a[i] == x) {
    		continue;
    	}
    	bool flag = false;
    	for (i64 j = 0; j < 30; ++ j) {
    		for (i64 k = 0; k < 30; ++ k) {
    			if (a[i] + (1ll << j) - (1ll << k) == x) {
    				++ cnt1[j];
    				++ cnt2[k];
    				flag = true;
    			}
    		}
    	}

    	if (!flag) {
    		std::cout << "NO\n";
    		return;
    	}
    }

    for (int i = 0; i < 30; ++ i) {
    	if (cnt1[i] != cnt2[i]) {
    		std::cout << "NO\n";
    		return;
    	}
    }

    std::cout << "YES\n";
}

D2. Candy Party (Hard Version)

题意:跟D1一样,不过每个人可以选择给或不给。

发现如果这个人只给或者只接受,那么它和平均数的差是2的幂。例如ai>x,则可以表示为+2i,0,或者+2i+1,2i。我们需要考虑应该选择哪一种。
发现这个只和两位有关,那么我们从高往低考虑,如果当前位的给出和收入不为0,就可以把+2i,0的变成+2i+1,2i

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<i64> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    i64 sum = std::accumulate(a.begin(), a.end(), 0ll);
    if (sum % n) {
    	std::cout << "NO\n";
    	return;
    }


    i64 x = sum / n;
    std::vector<int> cnt1(30), cnt2(30);
   	std::vector<int> sum1(30), sum2(30);
    for (int i = 0; i < n; ++ i) {
    	if (a[i] == x) {
    		continue;
    	}

    	bool flag = false;
    	for (i64 j = 0; j < 30; ++ j) {
    		if (a[i] - (1ll << j) == x) {
    			++ sum1[j];
    			flag = true;
    			break;
    		}
    	}

    	for (i64 j = 0; j < 30; ++ j) {
    		if (a[i] + (1ll << j) == x) {
    			++ sum2[j];
    			flag = true;
    			break;
    		}
    	}

    	if (flag) {
    		continue;
    	}

    	flag = false;
    	for (i64 j = 0; j < 30; ++ j) {
    		for (i64 k = 0; k < 30; ++ k) {
    			if (a[i] + (1ll << j) - (1ll << k) == x) {
    				++ cnt1[k];
    				++ cnt2[j];
    				flag = true;
    			}
    		}
    	}

    	if (!flag) {
    		std::cout << "NO\n";
    		return;
    	}
    }

    for (int i = 29; i ; -- i) {
    	int d = (cnt1[i] - cnt2[i] + sum1[i] - sum2[i]);
    	if (d > 0) {
    		if (sum2[i - 1] < d) {
    			std::cout << "NO\n";
    			return;
    		}

    		sum2[i - 1] -= d;
    		cnt1[i - 1] += d;
    	} else if (d < 0) {
    		d = -d;
    		if (sum1[i - 1] < d) {
    			std::cout << "NO\n";
    			return;
    		}

    		sum1[i - 1] -= d;
    		cnt2[i - 1] += d;
    	}
    }

    if (cnt1[0] - cnt2[0] + sum1[0] - sum2[0] != 0) {
    	std::cout << "NO\n";
    	return;
    }

    std::cout << "YES\n";
}
posted @   maburb  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示