1.6 vp Polynomial Round 2022 (Div. 1 + Div. 2, Rated, Prizes!)

A - Add Plus Minus Sign

题意:给出01字符串,可以在每两个字符中间任意添加‘+’,‘-’。最后要使表达式的绝对值最小
思路:设表达式的值为\(cnt\),若当前\(cnt\)大于\(0\),不管是0,还是1,都要添加‘-’,如果是1,那么cnt--
若当前\(cnt\)小于等于\(0\),不管是0,还是1,都要添加‘+’,如果是1,那么cnt++

void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	int cnt = 0;
	string st;
	if (s[0] == '1') cnt ++;
	for (int i = 1; i < s.size(); i ++) {
		if (cnt > 0) {
			st += '-';
			if (s[i] == '1') cnt --;
		}
		else {
			st += '+';
			if (s[i] == '1') cnt ++;
		}
	}
	
	cout << st << endl;
}

\[\]

B - Coloring

题意:给出n个格子,每个格子都要涂上颜色,给出m种颜色,每种颜色有\(a_i\)个,其中每k个格子不能有相同颜色,问是否有满足条件的答案
思路:将n个格子分为k份,每一份只涂k种不同颜色。
设n / t为 \(rd\) , n % t为 \(late\) ,\(late\)表示\(a_i\)最多有\(rd + 1\),且数量不超过\(late\)
\(a_i\)大于\(rd + 1\),说明不可能满足条件,NO。若\(a_i\)等于\(rd + 1\)的数目多于\(late\)也不满足条件,NO。否则YES

void solve() {
	int n, m, k;
	cin >> n >> m >> k;
	for (int i = 1; i <= m; i ++) {
		cin >> a[i];
	}
	
	sort(a + 1, a + 1 + m, greater<int>());
	
	int late = n % k, rd = n / k;
	bool ok = 1;
	for (int i = 1; i <= m; i ++) {
		if (a[i] <= rd) continue;
		else {
			if (late && a[i] - 1 == rd) {
				late --;
				continue;
			}else {
				ok = 0;
				break;
			}
		}
	}
	
	if (ok) cout << "YES" << endl;
	else cout << "NO" << endl;
}

\[\]

C - Ice and Fire

题意:共有\(n\)个人和\(n - 1\)场比赛,第\(i\)个人的能力值是\(i\)\(n - 1\)场比赛规则由01字符串决定,0表示能力值小的获胜,1表示能力值大的获胜。只要场上多于1一个人,就继续根据字符串的顺序进行对战。求人数从\(2\) ~ \(n\),每轮最多有多少人获胜。
思路:根据数据和推算可知,每轮最后一个字符可以将一个人踢出获胜序列。如1 2 3 4, 比赛规则是001,最后一个字符是1,则1绝不可能获胜。
那么若是后缀有连续的0或1,则可以连续限定范围。故每轮只需要统计后缀上最大的0或1的数量\(t\),每轮总个数减去\(t\)即为所求。

void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	int cnt1 = 0, cnt0 = 0;
	for (int i = 0; i < n - 1; i ++) {
		if (s[i] == '0') {
			cnt1 = 0;
			cnt0 ++;
		} else {
			cnt1 ++;
			cnt0 = 0;
		}
		
		cout << i + 2 - max(cnt1, cnt0) << ' ';
	}
	cout << endl;
}

\[\]

D - Same Count One

题意:给出n个长度为m的01字符串,可以对不同的两个字符串交换同一位置的字符,问是否能通过操作,使每个字符串中的1的数量相等。如果不能则输出-1。
思路:先统计\(n * m\)个字符中1的数量\(sum\)和每个字符串中1的数量\(s_i\)。若\(sum\) / \(n\) != 0说明不可能满足条件,输出-1。
若满足条件,按列枚举\(s_i\),\(ave = sum / n\),将小于\(ave\)和大于\(ave\)的行放入不同集合。然后两两匹配。最后输出即可。

struct ans{
	int x, y, z;
};
 
//注意观察N的大小
void solve() {
	int n, m;
	cin >> n >> m;
	vector<vector<int>> v(n + 1, vector<int>(m + 1));
	int sum = 0;                                          //统计总共1的个数
	vector<int> s(n + 1);                                  //统计每行1的个数
	for (int i = 1; i <= n; i ++) {
		s[i] = 0;
		for (int j = 1; j <= m; j ++) {
			cin >> v[i][j];
			sum += v[i][j];
			s[i] += v[i][j];
		}
	}
	
	if (sum % n != 0) {
		cout << -1 << endl;
		return ;
	}
	
	vector<ans> res;                                      //答案数组
	vector<int> big, small;
	int ave = sum / n;
	
	for (int i = 1; i <= m; i ++) {
		
		for (int j = 1; j <= n; j ++) {
			if (s[j] < ave && v[j][i] == 0) small.push_back(j);
			if (s[j] > ave && v[j][i] == 1) big.push_back(j);
		}
		
		for (int j = 0; j < min(big.size(), small.size()); j ++) {
			s[big[j]] --, s[small[j]] ++;
			res.push_back({big[j], small[j], i});
		}
		
		small.clear(), big.clear();
	}
	
	cout << res.size() << endl;
	for (auto i : res) cout << i.x << ' ' << i.y << ' ' << i.z << endl;
}

总结:对于某些题很快能有思路,如B题,但很多简单题却麻爪,如C题。一是思路有些陷入经验主义,以为要统计字符串整体的01数量,其实多加了一个连续后缀就没想到。二是很多没想清楚怎么实现。

posted @ 2023-01-06 16:11  nobodyL  阅读(38)  评论(0)    收藏  举报