codeforces round#615 div3题解

比赛连接
A
题意:
给你三个人分别有的糖果数,现在你是老大,你有很多糖果要分给这三个人,条件是最后三个人的糖果数要一样多,并且你的糖果要发光,不能有剩余。

思路:
先让每个人的糖果数相同,如果还有糖果剩余,那就判断是不是最后能每个人的糖果数都一样。

#include <bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
 
using namespace std;
 
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
 
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//1.integer overflow(maybe even long long overflow : ++ -> - )  a + b >= c -> a >= c - b
//2.runtime error
//3.boundary condition
i64 t, a[3], n;
 
int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("in", "r", stdin);
#endif
	
	cin >> t;
	while (t--) {
		cin >> a[0] >> a[1] >> a[2] >> n;
		sort(a, a + 3);
		i64 gap = a[2] - a[1] + a[2] - a[0];
		n -= gap;
		if (n < 0) cout << "NO" << '\n';
		else {
			if (n % 3 == 0) cout << "YES" << '\n';
			else cout << "NO" << '\n';
		}
	}
		
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

B
题意:
给你张有很多点的图,你只能向上或向右走,让你走过所有的点, 并且要走的顺序字典序最小(能往右就往右),如不能就输出no。

#include <bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
 
using namespace std;
 
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
 
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//1.integer overflow(maybe even long long overflow : ++ -> - )  a + b >= c -> a >= c - b
//2.runtime error
//3.boundary condition
const int maxn = 1100;
int t, n;
 
int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("in", "r", stdin);
#endif
	
	cin >> t;
	while (t--) {
		cin >> n;
		vpi a(n);
		forn(i, n) {
			cin >> a[i].fi >> a[i].se;
		}
		sort(a.begin(), a.end());
		bool ok = true;
		forn(i, n - 1) {
			ok &= (a[i].se <= a[i + 1].se);
		}
		if (!ok) {
			cout << "NO" << '\n';
			continue;
		}
		cout << "YES" << '\n';
		int nowX = 0, nowY = 0;
		string ans = "";
		forn(i, n) {
			int rNum = a[i].fi - nowX;
			int uNum = a[i].se - nowY;
			forn(j, rNum) ans += 'R';
			forn(j, uNum) ans += 'U';
			nowX = a[i].fi;
			nowY = a[i].se;
		}
		cout << ans << '\n';
	}
		
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

C
题意:
给你一个整数n,让你找三个不同的整数a, b, c,使得a * b * c等于n,如果没有的话就输出NO。

思路:
1.先找最小的因子,然后找第二小的因子,然后得出第三小的因子,看合不合法。(好麻烦,不如直接暴力枚举)
2.O(sqrt(n) ^ 2)暴力枚举第一个和第二个因子,得出c,看c合不合法,如果n%a不等于0就不用遍历第二个因子了(不然会超时 1e4*1e4)

#include <bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
 
using namespace std;
 
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
 
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//1.integer overflow(maybe even long long overflow : ++ -> - )  a + b >= c -> a >= c - b
//2.runtime error
//3.boundary condition
i64 t, n, a, b, c;
 
bool isPrime(i64 x) {
	bool ok = true;
	for (i64 i = 2; i * i <= x; ++i) {
		ok &= (x % i != 0);
	}
	return ok;
}

int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("in", "r", stdin);
#endif
	
	cin >> t;
	while (t--) {
		a = b = c = -1;
		cin >> n;
		i64 tn = n;
		if (isPrime(n)) {
			cout << "NO" << '\n';
			continue;
		}
		for (i64 i = 2; i * i <= n; ++i) {
			if (n % i == 0) {
				a = i;
				n /= i;
				break;
			}
		}
		for (i64 i = a + 1; i * i <= n; ++i) {
			if (n % i == 0) {
				b = i;
				n /= i;
				break;
			}
		}                                                  		
		c = tn / a / b;
		if (c == a || c == b || c < 2 || a == -1 || b == -1) cout << "NO" << '\n';
		else {
			cout << "YES" << '\n';
			cout << a << " " << b << " " << c << '\n';
		}
	}
		
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

D
题意:
给你n个事件,每次操作能把当天一个事件或者±x天的时间去掉,问你最近一天的时间是啥。(要使这个最近时间最大)。

思路:贪心,每次操作肯定把他能去掉的最近的那天去掉,利用set或map维护一下O(nlogn),或设一个变量保存当前最小可能的答案,若不行就向后O(1)推就行。

#include <bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
 
using namespace std;
 
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
 
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//1.integer overflow(maybe even long long overflow : ++ -> - )  a + b >= c -> a >= c - b
//2.runtime error
//3.boundary condition
int now = 0, q, x, y;
map<int, int> vis;
map<int, int> cnt;
 
int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("in", "r", stdin);
#endif
	
	cin >> q >> x;
	for (int i = 0; i < q; ++i) {
		cin >> y;
		int rem = y % x;
		if (rem + cnt[rem] * x > q) {
			cout << now << '\n';
			continue;
		}
		vis[rem + cnt[rem] * x] = 1;
		++cnt[rem];
		while (vis[now] == 1) ++now;
		cout << now << '\n';
	}
	
		
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

E
题意:
给你一个矩阵,每次操作都能对某一列进行向上移1位的cycle,或者将某个位置的数替换成任意一个数, 问你最少需要几次操作才能获得一个有序的矩阵。

思路:
把每一列单独拿出来考虑,遍历所有可能的移位,取这列移几位+移位后需要改的数的个数的最小值并更新答案,对每一列做这个操作即可。

#include <bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
 
using namespace std;
 
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
 
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//1.integer overflow(maybe even long long overflow : ++ -> - )  a + b >= c -> a >= c - b
//2.runtime error
//3.boundary condition
const int maxn = 2 * (int)1e5 + 1000;
int n, m;
 
int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("in", "r", stdin);
#endif
	
	cin >> n >> m;
	vector< vector<int> > a(n, vector<int>(m));
	forn(i, n) {
		forn(j, m) {
			cin >> a[i][j];
			--a[i][j];
		}
	}
	int sum = 0;
	forn(j, m) {
		vi cnt(n, 0);
		forn(i, n) {
			if (a[i][j] > n * m - 1) continue;
			if (a[i][j] % m == j) {
				int pos = a[i][j] / m;
				++cnt[(i - pos + n) % n];
			}
		}
		int cur = INT_MAX;
		fore(i, 0, n - 1) {
			uin(cur, i + (n - cnt[i])); //shift + numbers need to be modified
		}
		sum += cur;
	}
	cout << sum << '\n';
		
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

F
题意:
给你一个图,让你选三个点,这三个点的连起来后包含的路最多。

思路:
1.dp(待补)
2.选直径,然后再选离直径最远的那个点即可,现在来证明为什么选直径最优,如果不选直径的话,假设选了三个a, b, c,假设直径两点为da, db, 现在我们让da和a, b, c任意一点相连, 有一段路径和a, b, c的路径是重合的,不重合的那段就是da和db的连线,也就是树的直径,那这个直径肯定大于等于任何两个点的距离,所以选直径的两个点肯定是必要的,然后再选一个离直径最远的点就是最优的了。
proof by contradiction .Suppose take any three paths not involving the diameter .Then take the diameter and connect one of the vertices of diameter with vertex on three paths and take one of the branch .Since the branch left has length shorter than the diameter hence contradiction .

#include <bits/stdc++.h>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
 
using namespace std;
 
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
 
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
//1.integer overflow(maybe even long long overflow : ++ -> - )  a + b >= c -> a >= c - b
//2.runtime error
//3.boundary condition
int n, a, b;
vi p;
vvi g;
 
pii dfs(int v, int par = -1, int dist = 0) {
	p[v] = par;   	
	pii res = make_pair(dist, v);
	for (auto to : g[v]) {
		if (to == par) continue;
		res = max(res, dfs(to, v, dist + 1));
	}
	return res;
}

int main() {
	ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("in", "r", stdin);
#endif
	
	cin >> n;
	p = vi(n);
	g = vvi(n);
	forn(i, n - 1) {
		cin >> a >> b;
		--a; --b;
		g[a].pb(b);
		g[b].pb(a);
	}
	pii da = dfs(0);
	pii db = dfs(da.se);
	vi diam;
	int v = db.se;
	while (v != da.se) {
		diam.pb(v);
		v = p[v];
	}
	diam.pb(da.se);
	if (int(diam.size()) == n) {
		cout << n - 1 << '\n';
		cout << diam[0] + 1 << " " << diam.back() + 1 << " " << diam[1] + 1 << '\n';
	} else {
		queue<int> q;
		vi d(n, -1);
		for (auto v : diam) {
			d[v] = 0;
			q.push(v);
		}
		while (!q.empty()) {
			int v = q.front();
			q.pop();
			for (auto to : g[v]) {
				if (d[to] == -1) {
					d[to] = d[v] + 1;
					q.push(to);
				}
			}
		}
		pii mx = make_pair(d[0], 0);
		for (int i = 1; i < n; ++i) {
			uax(mx, make_pair(d[i], i));
		}
		cout << int(diam.size()) - 1 + mx.fi << '\n';
		cout << diam[0] + 1 << " " << diam.back() + 1 << " " << mx.se + 1 << '\n';
	}
		
#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
	return 0;
}

还是太菜了鸭,比赛时不做E先做F真是个错误的决定,D也因为比赛时写的set+map太复杂改了好多次错了三发巨难受,写完D还剩半个小时,看了F是图论而且是div3的图论就很有信心的做了,最后还是没过:<, 以后cf比赛后期至少要往后看两道题吧, 不然卡住就直接gg了。

发布了51 篇原创文章 · 获赞 6 · 访问量 1595

猜你喜欢

转载自blog.csdn.net/qq_43555854/article/details/104085818