2020杭电多校第四场题解

2020 Multi-University Training Contest 4


施工中。。。

1002 Blow up the Enemy

签到题,只需要计算每把武器造成至少100伤害的时间,求出最少时间武器的数量,然后计算胜率即可。

比赛时一发过。

#include<bits/stdc++.h>
#define ll long long
#define maxn 100010
#define mod 1000000007
using namespace std;
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int n;
		scanf("%d", &n);
		int sum = 0, ma = 1e9;
		for (int i = 0; i < n; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			int tp = ((100 + x - 1) / x - 1) * y;
			if (tp < ma) ma = tp, sum = 1;
			else if (tp == ma) sum++;
		}
		printf("%.8lf\n", 1.0 - 0.5 * sum / n);
	}
	return 0;
}

1003 Contest of Rope Pulling

题目看上去像是一个背包问题,但如果使用朴素的背包方法会T。

所以可以将物品的容量分为正负两种,依次进行背包操作,答案保持在0处。

由于物品大小不大,所以对数组进行随机排序,缩小背包的大小,答案正确率处于很高水平。

最后一小时尝试过,使用按大小排序方式不行,然后随机排序后就过了,只能说是运气好。

#include<bits/stdc++.h>
#define ll long long
#define maxn 300010
#define mod 1000000007
using namespace std;
ll dp[maxn];
ll inf = -1e15;
struct cv {
	ll x, y;
}a[maxn], b[maxn], c[maxn];
bool cmp(cv p, cv q) {
	return p.y > q.y;
}
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 0; i < n; i++) scanf("%lld%lld", &a[i].x, &a[i].y);
		for (int i = 0; i < m; i++) scanf("%lld%lld", &b[i].x, &b[i].y);
		random_shuffle(a, a + n);
		random_shuffle(b, b + m);
		int cnt = 0;
		for (int i = 0; i < min(n, m); i++) {
			c[cnt++] = a[i];
			b[i].x *= -1;
			c[cnt++] = b[i];
		}
		if (n > m) for (int i = m; i < n; i++) c[cnt++] = a[i];
		else for (int i = n; i < m; i++) {
			b[i].x *= -1; c[cnt++] = b[i];
		}
		for (int i = 0; i < maxn; i++) dp[i] = inf;
		dp[maxn / 2] = 0;
		for (int i = 0; i < cnt; i++) {
			if (c[i].x > 0) {
				for (ll j = maxn - 1; j - c[i].x >= 0; j--) {
					dp[j] = max(dp[j], dp[j - c[i].x] + c[i].y);
				}
			}
			else {
				for (ll j = 0; j - c[i].x < maxn; j++) dp[j] = max(dp[j], dp[j - c[i].x] + c[i].y);
			}
		}
		printf("%lld\n", dp[maxn / 2]);
	}
	return 0;
}

1004 Deliver the Cake

求最短路的模板题,在计算距离的时候处理一下是左手还是右手拿蛋糕就可以了。

由于中途转换过程处理出了一些问题导致WA2,想清楚后就解决了。

#include<bits/stdc++.h>
#define ll long long
#define maxn 200010
#define mod 1000000007
using namespace std;
vector<int>b[maxn];
vector<ll>c[maxn];
char a[maxn];
int pe[maxn];
ll ans[maxn][3];
struct cv {
	int x, pe;
	ll y;
	friend bool operator<(cv p, cv q) {
		return p.y > q.y;
	}
}dd, bb;
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int n, m, s, e;
		ll x;
		scanf("%d%d%d%d%lld", &n, &m, &s, &e, &x);
		scanf("%s", a + 1);
		for (int i = 1; i <= n; i++) {
			if (a[i] == 'L') pe[i] = 1;
			else if (a[i] == 'R') pe[i] = 2;
			else pe[i] = 3;
			vector<int>v;
			swap(v, b[i]);
			vector<ll>vv;
			swap(vv, c[i]);
			ans[i][1] = ans[i][2] = 0;
		}
		for (int i = 0; i < m; i++) {
			int l, r;
			ll z;
			scanf("%d%d%lld", &l, &r, &z);
			b[l].push_back(r);
			c[l].push_back(z);
			b[r].push_back(l);
			c[r].push_back(z);
		}
		dd.x = s, dd.y = 0;
		priority_queue<cv>q;
		if (pe[s] & 1) {
			dd.pe = 1;
			q.push(dd);
		}
		if (pe[s] & 2) {
			dd.pe = 2;
			q.push(dd);
		}
		while (!q.empty()) {
			dd = q.top();
			q.pop();
			int now = dd.x;
			if (dd.y != ans[now][dd.pe]) continue;
			if (now == e) break;
			for (int i = 0; i < b[now].size(); i++) {
				bb.x = b[now][i], bb.y = dd.y + c[now][i];
				if ((dd.pe & pe[bb.x]) == 0) {
					bb.pe = pe[bb.x];
					bb.y += x;
				}
				else bb.pe = dd.pe;
				if (ans[b[now][i]][bb.pe] == 0) {
					ans[b[now][i]][bb.pe] = bb.y;
					q.push(bb);
				}
				else if (ans[b[now][i]][bb.pe] > bb.y) {
					ans[b[now][i]][bb.pe] = bb.y;
					q.push(bb);
				}
			}
		}
		if (ans[e][1] == 0) printf("%lld\n", ans[e][2]);
		else if (ans[e][2] == 0) printf("%lld\n", ans[e][1]);
		else printf("%lld\n", min(ans[e][1], ans[e][2]));
	}
	return 0;
}

1005 Equal Sentences

对于每个相邻字符不同的串,相邻的两个数可以交换,但是不能连续交换

通过 \(dp\) 可以得到,不同的串的个数就是斐波那契数列

计算的时候,连续相同的数阶段截断即可

比赛时一发过。

#include<bits/stdc++.h>
#define ll long long
#define maxn 200010
#define mod 1000000007
using namespace std;
int a[maxn];
ll dp[maxn];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	int t;
	cin >> t;
	dp[0] = 1;
	dp[1] = 1;
	for (int i = 2; i < maxn; i++) {
		dp[i] = dp[i - 1] + dp[i - 2];
		dp[i] %= mod;
	}
	while (t--) {
		int n;
		map<string, int>mp;
		int cnt = 0;
		cin >> n;
		for (int i = 1; i <= n; i++) {
			string tp;
			cin >> tp;
			if (mp.count(tp)) a[i] = mp[tp];
			else {
				mp[tp] = cnt;
				a[i] = cnt++;
			}
		}
		ll ans = 1;
		ll sum = 1;
		for (int i = 2; i <= n; i++) {
			if (a[i] == a[i - 1]) {
				ans = ans * dp[sum] % mod;
				sum = 1;
			}
			else sum++;
		}
		ans = ans * dp[sum] % mod;
		printf("%lld\n", ans);
	}
	return 0;
}

1007 Go Running

对于每条记录,我们令他都是有一个从 \(t=0\) 的时刻就开始跑的人经过的,那这个人可以同时经过的点都是最多的

对于每条记录,可能会有两个人,即一个从东向西跑,一个从西向东跑

我们对两个人建边,就可以建成一个二分图

对于每条边都需要一条个点,即最小点覆盖

原先用贪心思想WA了一发,使用不太靠谱的模板T了一发,模板改错又WA了一发,最后发现问题才过了。

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;

const int MAXN = 200010;
const int MAXM = 200010;
const int INF = 2147483647;
struct Edge {
	int v;
	int next;
} edge[MAXM];


int nx, ny;
int cnt;
int t;
int dis;

int first[MAXN];
int xlink[MAXN], ylink[MAXN];
/*xlink[i]表示左集合顶点所匹配的右集合顶点序号,ylink[i]表示右集合i顶点匹配到的左集合顶点序号。*/
int dx[MAXN], dy[MAXN];
/*dx[i]表示左集合i顶点的距离编号,dy[i]表示右集合i顶点的距离编号*/
int vis[MAXN]; //寻找增广路的标记数组

void init() {
	cnt = 0;
	memset(first, -1, sizeof(first));
	memset(xlink, -1, sizeof(xlink));
	memset(ylink, -1, sizeof(ylink));
}

void read_graph(int u, int v) {
	edge[cnt].v = v;
	edge[cnt].next = first[u], first[u] = cnt++;
}

int bfs() {
	queue<int> q;
	dis = INF;
	memset(dx, -1, sizeof(dx));
	memset(dy, -1, sizeof(dy));
	for (int i = 0; i < nx; i++) {
		if (xlink[i] == -1) {
			q.push(i);
			dx[i] = 0;
		}
	}
	while (!q.empty()) {
		int u = q.front();
		q.pop();
		if (dx[u] > dis) break;
		for (int e = first[u]; e != -1; e = edge[e].next) {
			int v = edge[e].v;
			if (dy[v] == -1) {
				dy[v] = dx[u] + 1;
				if (ylink[v] == -1) dis = dy[v];
				else {
					dx[ylink[v]] = dy[v] + 1;
					q.push(ylink[v]);
				}
			}
		}
	}
	return dis != INF;
}

int find(int u) {
	for (int e = first[u]; e != -1; e = edge[e].next) {
		int v = edge[e].v;
		if (!vis[v] && dy[v] == dx[u] + 1) {
			vis[v] = 1;
			if (ylink[v] != -1 && dy[v] == dis) continue;
			if (ylink[v] == -1 || find(ylink[v])) {
				xlink[u] = v, ylink[v] = u;
				return 1;
			}
		}
	}
	return 0;
}

int MaxMatch() {
	int ans = 0;
	while (bfs()) {
		memset(vis, 0, sizeof(vis));
		for (int i = 0; i < nx; i++) if (xlink[i] == -1) {
			ans += find(i);
		}
	}
	return ans;
}

int main() {
	int tt;
	scanf("%d", &tt);
	while (tt--) {
		init();
		int n;
		scanf("%d", &n);
		map<ll, int>mp1, mp2;
		int cntt = 0;
		set<ll>mep;
		for (int i = 0; i < n; i++) {
			ll x, y;
			scanf("%lld%lld", &x, &y);
			ll tu = x * (1e9 + 1) + y;
			if (mep.count(tu)) continue;
			else mep.insert(tu);
			ll id1, id2;
			if (mp1.count(x - y)) id1 = mp1[x - y];
			else {
				mp1[x - y] = cntt;
				id1 = cntt;
				cntt++;
			}
			if (mp2.count(x + y)) id2 = mp2[x + y];
			else {
				mp2[x + y] = cntt;
				id2 = cntt;
				cntt++;
			}
			read_graph(id1, id2);
		}
		nx = cntt; ny = cntt;
		int ans = MaxMatch();
		printf("%d\n", ans);
	}
	return 0;
}

1011 Kindergarten Physics

由于万有引力太小,可以忽略不记,直接输出原距离即可。

比赛时一发过。

#include <bits/stdc++.h>
#define db double
using namespace std;
const db g = 6.67430 * 1e-11;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    int t; cin >> t;
    while (t--) {
        db a, b, d, t;
        cin >> a >> b >> d >> t;
        cout << d << '\n';
    }
    return 0;
}

1012 Last Problem

构造题,对于每个数字写下之前保证周围有比它小1-4的数字,所以考虑递归先放小的数字。

同时记录小每个位置的数字,如果已经放上了要求的数,便无需再填写。

比赛时一发过。

#include<bits/stdc++.h>
#define ll long long
#define maxn 300010
#define mod 1000000007
using namespace std;
int a[2000][2000];
int to[4][2] = { 0,-1,1,0,-1,0,0,1 };
void sol(int n, int x, int y) {
	for (int i = 0; i < 4; i++) {
		if (a[x + to[i][0]][y + to[i][1]] == n - i - 1) continue;
		if (n - i - 1 >= 1) sol(n - i - 1, x + to[i][0], y + to[i][1]);
	}
	printf("%d %d %d\n", x, y, n);
	a[x][y] = n;
}
int main() {
	int n;
	scanf("%d", &n);
	sol(n, 1000, 1000);
	return 0;
}
posted @ 2020-07-31 15:36  st1vdy  阅读(400)  评论(0编辑  收藏  举报