Educational Codeforces Round 105 (Rated for Div. 2) CE

这场的代码真的有点烦(
等手题解然后补题,先挖坑


待补题:

C (已)

D

E (已)


A

枚举字符串,判断是否合法

#include <bits/stdc++.h>
using namespace std;

bool check(char s[], int len) {
    
    
	bool flag = 0;
	int cnt = 0;
	for(int i = 0; i < len; ++ i) {
    
    
		if(s[i] == '(') cnt++;
		if(s[i] == ')') cnt--;
		if(cnt < 0) return 0;
	}
	if(cnt > 0) return 0;
	return 1;
}

bool check2(char s[], int len) {
    
    
	bool flag = 0;
	int cnt = 0;
	for(int i = 0; i < len; ++ i) {
    
    
		if(s[i] == ')') cnt++;
		if(s[i] == '(') cnt--;
		if(cnt < 0) return 0;
	}
	if(cnt > 0) return 0;
	return 1;
}

int main() {
    
    
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	int T;
	int n;
	cin >> T;
	while(T--) {
    
    
		string s;
		cin >> s;
		int len = s.size();
		char t[60];
		bool flag = 0;
		
		for(int i = 0; i < len; ++ i) {
    
    
			if(s[i] == 'A' || s[i] == 'B') t[i] = '(';
			else {
    
    
				t[i] = ')';
			}
		}
//		cout << t << endl;
		if(check(t, len) || check2(t, len)){
    
    
			flag = 1;
		}
		for(int i = 0; i < len; ++ i) {
    
    
			if(s[i] == 'A' || s[i] == 'C') t[i] = '(';
			else {
    
    
				t[i] = ')';
			}
		}
//		cout << t << endl;
		if(check(t, len) || check2(t, len)){
    
    
			flag = 1;
		}
		for(int i = 0; i < len; ++ i) {
    
    
			if(s[i] == 'B' || s[i] == 'C') t[i] = '(';
			else {
    
    
				t[i] = ')';
			}
		}
//		cout << t << endl;
		if(check(t, len) || check2(t, len)){
    
    
			flag = 1;
		}
		
		if(flag) cout << "YES\n";
		else cout << "NO\n";
	} 
} 

B

枚举四个角上的涂色情况,然后判断是否合法

#include <bits/stdc++.h>
using namespace std;

int mp[10];

int n;

bool check(int x, int cntx) {
    
    
	if(x < cntx) return 0;
	if(x - cntx > n - 2) return 0;
	return 1;
}

int main() {
    
    
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	int T;
	cin >> T;
	while(T--) {
    
    
		cin >> n;
		int u, r, d, l;
		cin >> u >> r >> d >> l;
		
		bool flag = 0;
		
		for(int i = 0; i < 16; ++ i) {
    
    
			for(int k = 0; k < 4; ++ k) {
    
    
				mp[k] = i >> k & 1;
			}
			int cntu = 0, cntr = 0, cntd = 0, cntl = 0;
			cntu = mp[0] + mp[1];
			cntr = mp[1] + mp[2];
			cntd = mp[2] + mp[3];
			cntl = mp[3] + mp[0];
			
//			cout << cntu << " " << cntr << " " << cntd << " " << cntl << endl;
//			system("pause");
			
			if(check(u, cntu) && check(r, cntr) && check(d, cntd) && check(l, cntl)) {
    
    
				flag = 1;	
				break;
			}
			
		}
		
		if(flag) cout << "YES\n";
		else cout << "NO\n";
		
	}
}

C. 1D Sokoban

题意: 有一个一维数轴,你刚开始在原点,有一些点上面有箱子,另有一些点被特殊标记,你可以推箱子但不能拉箱子,也不能越过箱子,问最多能有多少个箱子在标记的位置上

T ≤ 1000 , − 1 e 9 ≤ a i & & b i ≤ 1 e 9 , ∑ n ≤ 2 e 5 ∑ m ≤ 1 e 5 T \leq 1000, -1e9 \leq a_i \&\& b_i \leq 1e9 , \sum n \leq 2e5 \sum m \leq 1e5 T1000,1e9ai&&bi1e9,n2e5m1e5

思路: 原点左右可以分开做,把原点左边部分映射到右边,于是只用计算正数

昨晚的想法是:根据特殊标记做一个后缀和(多少个箱子已经正好被摆在标记位置上),枚举每个特殊标记的位置作为推箱子的最后一个点(会有连续的箱子,最后一个箱子刚好在枚举的位置),用lowerbound和upperbound判断这段连续的箱子有多少个在标记上,加上枚举点后一个点的后缀和 复杂度大概是nlogn常数可能有点大 ,wa2的第29个点,一时半会de不出来等一手官方题解

扫描二维码关注公众号,回复: 13048159 查看本文章

upd: 忘记判断如果在A里面upper_bound不存在的情况了((

#include <bits/stdc++.h>
using namespace std;

vector<int> al, ar, bl, br;

inline void init() {
    
    
	al.clear(), ar.clear();
	bl.clear(), br.clear();
}

int solve(const vector<int>& a, const vector<int>& b) {
    
    
	int n = a.size(), m = b.size();
	if(n == 0 || m == 1) return 0;
	
	vector<int> suf(m + 5);
	int j = n - 1;
	for(int i = m - 1; i >= 0; -- i) {
    
    
		suf[i] = suf[i + 1];
		if(j == -1) continue;
		while(a[j] > b[i] && j > 0) --j; 
		if(a[j] == b[i]) ++ suf[i], -- j;
	} 
	
	int ans = 0;
	for(int i = 1; i < m; ++ i) {
    
    
		int res = suf[i + 1];
		int pos = 0;
		if(upper_bound(a.begin(), a.end(), b[i]) == a.end()) pos = n; 
		else pos = upper_bound(a.begin(), a.end(), b[i]) - a.begin();
		int pp = b[i] - pos + 1;
		int l = lower_bound(b.begin(), b.end(), pp) - b.begin();
		res += i - l + 1;
		ans = max(ans, res);
	}
	return ans;
}

int main() {
    
    
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	int T;
	cin >> T;
	while(T--) {
    
    
		int n, m;
		cin >> n >> m;
		init();
		bl.push_back(0); br.push_back(0); 
		for(int i = 0, x; i < n; ++ i) {
    
    
			cin >> x;
			if(x < 0) al.push_back(-x);
			else ar.push_back(x);
		}
		for(int i = 0, x; i < m; ++ i) {
    
    
			cin >> x;
			if(x < 0) bl.push_back(-x);
			else br.push_back(x);
		}
		
		sort(al.begin(), al.end()); sort(bl.begin(), bl.end());	
		cout << solve(al, bl) + solve(ar, br) << endl;
	}
}

E. A-Z Graph

题意: n个点m次操作,每次操作有三种1.可以加一条边(边上有字母),2.删去一条边,3.询问是否能有经过k个点的往返路
径,并且使得往返边上字母连成的字符串相同

n,m 2e5

思路: 简单画图可得,k为奇成立的条件是存在两个点之间有双向的边,k为偶成立的条件是存在两个点之间有双向的边并且边上的字母相同

在这里插入图片描述

code : // 这里pair用struct在map判断是否存在的时候会有点问题,存疑

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;

#define first x
#define second y

map<pii , char> mp;

int main() {
    
    
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	 
	int n, m;
	cin >> n >> m;
	char op, ch;
	int x, y, cnt1 = 0, cnt2 = 0;
	
	for(int i = 0; i < m; ++ i) {
    
    
		
		cin >> op;
		if(op == '+') {
    
    
			cin >> x >> y >> ch;
			mp[{
    
    x, y}] = ch;
			if(mp.count({
    
    y, x})) {
    
    
				cnt1++;
				char p = mp[{
    
    y, x}];
				if(p == ch) cnt2 ++;
			}
//			cout << " cnttt::  " <<  cnt1 <<" " << cnt2 << endl;
		}
		else if(op == '-') {
    
    
			cin >> x >> y;
			char p1 = mp[{
    
    x, y}];
			mp.erase({
    
    x, y});
			if(mp.count({
    
    y, x})) {
    
    
				cnt1--;
				char p2 = mp[{
    
    y, x}];
				if(p1 == p2) cnt2--;
			}
		}
		else if (op == '?') {
    
    
			cin >> x;
//			cout << " cnttt::  " <<  cnt1 <<" " << cnt2 << endl;
			if(x & 1) {
    
    
				if(cnt1) cout << "YES\n";
				else cout << "NO\n";
			}
			else {
    
    
				if(cnt2) cout << "YES\n";
				else cout << "NO\n";
			} 
		}
	}
} 

猜你喜欢

转载自blog.csdn.net/qq_39602052/article/details/114308536