2018 计蒜之道 初赛 第一场 部分题解

比赛链接

昨天不在状态直接摸鱼到200+了。

题解包括abc题,d题因为难度太大本人没码出来。

由于题目是中文题所以题解不会有题目简述

虽然bc题题意相同数据量不同,笔者还是会提供不同的思路。

A 百度无人车

显然就是不断把最大的变成次大的过程,

首先用s/p算出最多能减少的kg数。

然后排序从大到小把第i个的重量变成第i+1个的重量。

如果所有车都变成同一重量(也就是变成最小那辆车的重量)在判断能不能把所有的车都变成重量为1就行了

不能的话就总体减去剩余的 可减次数/n。

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = 2*(int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double PI = acos(-1);
LL num[maxn];
bool cmp(LL a, LL b) {
	return a > b;
}
int main() {
	int n;
	while (~scanf("%d", &n)) {
		for (int i = 0; i < n; i++)
			scanf("%lld", &num[i]);
		sort(num, num + n,cmp);
		LL p, s;
		scanf("%lld%lld", &p, &s);
		LL cnt = s / p;
		LL ans = num[0], t = 1;
		for (int i = 1; i < n; i++) {
			if ((num[i-1] - num[i])*t <= cnt) {
				ans = num[i];
				cnt -= (num[i - 1] - num[i])*t;
				t++;
			}
			else break;
		}
		if (cnt > 0)
			ans -= cnt / t;
		if (ans <= 0) ans = 1;
		printf("%lld\n", ans);
	}
	return 0;
}

B 百度科学家(简单)

因为n只有20,那么把图建出来之后直接暴力就行了。

这里注意一点就是需要建立映射函数保证1操作下的建图正确性

暴力要注意的是对每一点进行dfs

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = 2*(int)1e4 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double PI = acos(-1);
map<int, int>mp;
vector<int>edge[100];
LL val[100];
LL tmp;
bool vis[100];
void dfs(int u) {
	tmp += val[u];
	vis[u] = 1;
	for (int i = 0; i < edge[u].size(); i++) {
		int v = edge[u][i];
		if (vis[v]) continue;
		dfs(v);
	}
}
int main() {
	int n;
	while (~scanf("%d", &n)) {
		mp.clear();
		for (int i = 0; i < 100; i++)
			edge[i].clear();
		for (int i = 1; i <= n; i++) {
			scanf("%lld", &val[i]);
			mp[i] = i;
		}
		int q, op, l, r, x;
		LL y;
		scanf("%d", &q);
		while (q--) {
			scanf("%d", &op);
			if (op == 0) {
				scanf("%d%lld", &x,&y);
				n++;
				val[n] = y;
				mp[x] = n;
			}
			else {
				scanf("%d%d%d", &x, &l, &r);
				for (int i = l; i <= r; i++) {
					edge[mp[x]].push_back(mp[i]);
				}
			}
		}
		LL ans = INF;
		for (int i = 1; i <= n; i++) {
			memset(vis, 0, sizeof(vis));
			tmp = 0;
			dfs(i);
			ans = min(tmp, ans);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

C 百度科学家(中等)

数据量变大了显然不能再暴力。

根据上一题的经验可知,如果我们对图进行缩点的话,我们要的结果一定在出度为0的点中。

所以先对图强连通缩点然后枚举出度为0的点找出最小值就行了。

建图方式跟前一题是一样的。

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = 2*(int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double PI = acos(-1);
map<int, int>mp;
LL vals[maxn];
struct tarjan {
	int dfn[maxn];//该节点被搜索的次序(时间戳)
	int low[maxn];//为i或i的子树能够追溯到的最早的栈中节点的次序号
	int stk[maxn];//栈模拟数组
	int col[maxn];//强联通分量染色
	int in[maxn], out[maxn];//入度出度
	bool vis[maxn];//是否在栈内
	LL val[maxn];
	vector<int>edge[maxn];//保存边
	int tot, coln, tops, n;//搜索次序,染色总数,栈顶,点数
	void init(int _n) {
		n = _n;
		for (int i = 1; i <maxn; i++) {
			dfn[i] = -1;
			col[i] = out[i] = low[i] = 0;
			edge[i].clear();
		}
		tot = tops = coln = 0;
	}
	void dfs(int u) {
		dfn[u] = low[u] = ++tot;
		stk[++tops] = u;
		vis[u] = true;
		for (int i = 0; i < edge[u].size(); i++) {
			int v = edge[u][i];
			if (dfn[v] == -1) {
				dfs(v);
				low[u] = min(low[u], low[v]);
			}
			else if (vis[v])
				low[u] = min(low[u], dfn[v]);
		}
		if (dfn[u] == low[u]) {
			int v;
			vector<int> ans;
			coln++;
			do {
				v = stk[tops--];
				vis[v] = false;
				col[v] = coln;
			} while (v != u);
		}
	}
	void solve() {
		for (int i = 1; i <= n; i++)
			if (dfn[i] == -1)
				dfs(i);
	}
	void dag() {
		for (int u = 1; u <= n; u++) {
			for (int i = 0; i < edge[u].size(); i++) {
				int v = edge[u][i];
				int x = col[u], y = col[v];
				if (x != y) {
					out[x]++;
				}
			}
		}
		memset(val, 0, sizeof(val));
		for (int u = 1; u <= n; u++)
			val[col[u]] += vals[u];
		LL ans = INF;
		for (int u = 1; u <= n; u++) {
			if (out[col[u]] == 0) {
				ans = min(ans, val[col[u]]);
			}
		}
		printf("%lld\n", ans);
	}
}tar;
int main() {
	int n;
	while (~scanf("%d", &n)) {
		tar.init(n);
		mp.clear();
		for (int i = 1; i <= n; i++) {
			scanf("%lld", &vals[i]);
			mp[i] = i;
		}
		int q, op, l, r, x;
		LL y;
		scanf("%d", &q);
		while (q--) {
			scanf("%d", &op);
			if (op == 0) {
				scanf("%d%lld", &x, &y);
				n++;
				vals[n] = y;
				mp[x] = n;
				tar.n++;
			}
			else {
				scanf("%d%d%d", &x, &l, &r);
				for (int i = l; i <= r; i++) {
					tar.edge[mp[x]].push_back(mp[i]);
				}
			}
		}
		tar.solve();
		tar.dag();
	}
	return 0;
}

d题因为数据量本身不能建图,所以笔者不会做

猜你喜欢

转载自blog.csdn.net/xiuya19/article/details/80297513