Codeforces Round #620 (Div. 2)

A
直接判断距离能否整除速度

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

int main()
{
	int t; scanf("%d", &t);
	while (t--) {
		int x, y, a, b; scanf("%d%d%d%d", &x, &y, &a, &b);
		if ((y - x) % (a + b))
			printf("-1\n");
		else
			printf("%d\n", (y - x) / (a + b));
	}
}

B
需要保留整个字符串,所以对每个字符串判断它的逆序字符串是否存在,存在就配对
最后判断剩下的字符串里面有没有自己是回文串的

#include <bits/stdc++.h>
using namespace std;
map<string, int> vis;
string ans, tmp, incre = "";
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n, m; cin >> n >> m;
	for (int i = 0; i < n; ++i) {
		cin >> tmp;
		reverse(tmp.begin(), tmp.end());
		if (vis.count(tmp) <= 0 || vis[tmp] <= 0) {
			reverse(tmp.begin(), tmp.end());
			vis[tmp]++;
		}
		else {
			ans += tmp;
			vis[tmp]--;
		}
	}
	for (map<string, int>::iterator res = vis.begin(); res != vis.end(); ++res) {
		if (res->second > 0) {
			bool flg = true;
			tmp = res->first;
			for (int i = 0; i < m / 2; ++i) {
				if (tmp[i] != tmp[m - i - 1]) {
					flg = false;
					break;
				}
			}
			if (flg) {
				incre = tmp;
				break;
			}
		}
	}
	cout << ans.size() * 2 + incre.size() << '\n';
	cout << ans + incre; reverse(ans.begin(), ans.end());
	cout << ans << '\n';
}

C

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 5;
ll t[maxn], l[maxn], h[maxn];
int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	int q; cin >> q;
	for (int i = 0; i < q; ++i) {
		int n, m; cin >> n >> m;
		for (int i = 1; i <= n; ++i)
			cin >> t[i] >> l[i] >> h[i];
		ll L = m, R = m; bool flg = false;
		for(int i = 1; i <= n; i++)
		{
			L = L - (t[i] - t[i - 1]);
			R = R + (t[i] - t[i - 1]);
			if (R < l[i] || L > h[i]) {
				flg = 1;
				break;
			}
			else {
				L = max(L, l[i]);
				R = min(R, h[i]);
			}
		}
		cout << (flg ? "NO" : "YES") << '\n';
	}
	return 0;
 }

D
考虑一种通用的构造
我们记录出现的>符号个数 c n t cnt cnt,则固定第一个数为 c n t + 1 cnt+1 cnt+1,出现 > > >从第一个数开始减小,但是出现 < < <需要记录个数
我们保证了从 c n t + 1 cnt+1 cnt+1开始递减的序列,要使上升子序列最,在保证满足 < < <的性质下从大的值开始使用
相同的,在保证 < < <的性质下,从小的开始用就可以使最

输入:7 >><>><
输出:最短:5 4 3 7 2 1 6,最长:5 4 3 6 2 1 7

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
char a[maxn];
int ans[maxn];
int main()
{
	int t; scanf("%d", &t);
	while (t--) {
		int n; scanf("%d%s", &n, a + 1);
		//min
		int cnt = 0, l, r, sum;
		for (int i = 1; i <= n - 1; ++i) {
			if (a[i] == '>')
				cnt++;
		}
		l = cnt, r = n, ans[1] = cnt + 1, sum = 0;
		for (int i = 1; i <= n - 1; ++i) {
			if (a[i] == '>') {
				if (sum) {
					for (int j = i; j >= i - sum + 1; --j)
						ans[j] = r--;
				}
				ans[i + 1] = l--;
				sum = 0;
			}
			else sum++;
		}
		if (sum) {
			for (int i = n; i >= n - sum + 1; --i)
				ans[i] = r--;
		}
		for (int i = 1; i <= n; ++i) {
			printf("%d%c", ans[i], i == n ? '\n' : ' ');
		}
		//max
		ans[1] = cnt + 1, l = cnt, r = cnt + 2, sum = 0;
		for (int i = 1; i <= n - 1; ++i) {
			if (a[i] == '>') {
				if (sum) {
					for (int j = i - sum + 1; j <= i; ++j)
						ans[j] = r++;
				}
				ans[i + 1] = l--;
				sum = 0;
			}
			else sum++;
		}
		if (sum) {
			for (int i = n - sum + 1; i <= n; ++i)
				ans[i] = r++;
		}
		for (int i = 1; i <= n; ++i)
			printf("%d%c", ans[i], i == n ? '\n' : ' ');
	}
}

E
在树上求给出两点 ( a , b ) (a,b) (a,b)间在 ( x , y ) (x,y) (x,y)之间建立一条边后是否存在经过 k k k条边的路径
注意:同一条边可以多次经过记录贡献
可以发现我们走同一条边来回一次对答案贡献是2,所以我们仅需要判断 k − k- k路径长度后的答案能不能整除2即可
树上求两点距离可以用 l c a lca lca

存在的路径有

  1. a → b a\rightarrow b ab
  2. a → x → y → b a\rightarrow x\rightarrow y\rightarrow b axyb
  3. a → y → x → b a\rightarrow y\rightarrow x\rightarrow b ayxb
  4. a → x → b a\rightarrow x\rightarrow b axb
  5. a → y → b a\rightarrow y\rightarrow b ayb

注意像 a → x → a → b a\rightarrow x\rightarrow a\rightarrow b axab这种存在重复路径的情况是不需要计算的,是包括在是否能整除2这个性质里面

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
vector<int> E[maxn];
int fa[maxn], sz[maxn], son[maxn], dep[maxn], top[maxn];
void dfs(int u, int f) {
	sz[u] = 1, fa[u] = f; dep[u] = dep[f] + 1;
	for (auto v : E[u]) {
		if (v == f) continue;
		dfs(v, u);
		sz[u] += sz[v];
		if (sz[v] > sz[son[u]]) son[u] = v;
	}
}
void dfs1(int u, int tf) {
	top[u] = tf;
	if (!son[u]) return;
	dfs1(son[u], tf);
	for (auto v : E[u]) {
		if (v == fa[u] || v == son[u]) continue;
		dfs1(v, v);
	}
}
int get_lca(int x, int y) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		x = fa[top[x]];
	}
	if (dep[x] > dep[y]) swap(x, y);
	return x;
}
int get_dis(int x, int y) {
	if (x > y) swap(x, y);
	if (x == y) return 0;
	return dep[x] + dep[y] - 2 * dep[get_lca(x, y)];
}
int q, x, y, a, b, k;
bool solve() {
	cin >> x >> y >> a >> b >> k;
	int dis_xy = get_dis(x, y);
	int dis_ab = get_dis(a, b);
	int dis_ax = get_dis(a, x);
	int dis_ay = get_dis(a, y);
	int dis_xb = get_dis(x, b);
	int dis_yb = get_dis(y, b);
	//cout << "xy=" << dis_xy << ",ab=" << dis_ab << ",ax=" << dis_ax << ",ay=" << dis_ay << ",xb=" << dis_xb << ",yb=" << dis_yb << endl;
	if (k >= dis_ab && (k - dis_ab) % 2 == 0)
		return true;
	if (k >= dis_ax + dis_xy + dis_yb && (k - dis_ax - dis_xy - dis_yb) % 2 == 0)
		return true;
	if (k >= dis_ax + 1 + dis_yb && (k - dis_ax - 1 - dis_yb) % 2 == 0)
		return true;
	if (k >= dis_ay + dis_xy + dis_xb && (k - dis_ay - dis_xy - dis_xb) % 2 == 0)
		return true;
	if (k >= dis_ay + 1 + dis_xb && (k - dis_ay - 1 - dis_xb) % 2 == 0)
		return true;
	if (k >= dis_ax + dis_xb && (k - dis_ax - dis_xb) % 2 == 0)
		return true;
	if (k >= dis_ay + dis_yb && (k - dis_ay - dis_yb) % 2 ==0)
		return true;
	return false;
}
int main()
{
	ios::sync_with_stdio(false); cin.tie(0);

	int n; cin >> n;
	for (int i = 1; i < n; ++i) {
		int u, v; cin >> u >> v;
		E[u].push_back(v);
		E[v].push_back(u);
	}
	dfs(1, 0); dfs1(1, 1);
	cin >> q;
	while (q--) {
		cout << (solve() ? "YES" : "NO") << '\n';
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值