1. 程式人生 > 實用技巧 >2020杭電多校第四場題解

2020杭電多校第四場題解

2020 Multi-University Training Contest 4


施工中。。。

1002 Blow up the Enemy

#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

#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

求最短路的模板題,在計算距離的時候處理一下是左手還是右手拿蛋糕就可以了

#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\) 的時刻就開始跑的人經過的,那這個人可以同時經過的點都是最多的

對於每條記錄,可能會有兩個人,即一個從東向西跑,一個從西向東跑

我們對兩個人建邊,就可以建成一個二分圖

對於每條邊都需要一條個點,即最小點覆蓋

#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

#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;
}