2019杭电多校第8场

1009 Calabash and Landlord
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6665

解题思路:
这道题目问我们整个平面被2个矩阵可以分成几个面i,相当于就在问有几个;这就相当于是在问我们整张图里面有几个联通快。所以可以直接离散化,然后让每个矩形内的方块 + 1;然后求存在几个连通块。

注意点:
1.需要注意 + 1 的时候需要注意范围
2.使用 + 1 的方法来判断连通快的个数,需要判断2个特殊的情况,

  1. 2个矩阵完全重合
    1. 2个矩阵刚好外切。

AC代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;

struct Node {
	int x1, y1, x2, y2;
}node[5];

int t;
int g[10][10];
vector<int> X, Y;
bool vis[50];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};

inline int get(int x, int y) {
	return (x - 1) * Y.size() + y;
}

inline int findx(int x) {
	int l = 0, r = X.size() - 1;
	while(l < r) {
		int mid = (l + r + 1) / 2;
		if(X[mid] <= x) l = mid;
		else r = mid - 1;
	}
	
	return l;
}

inline int findy(int x) {
	int l = 0, r = Y.size() - 1;
	while(l < r) {
		int mid = (l + r + 1) / 2;
		if(Y[mid] <= x) l = mid;
		else r = mid - 1;
	} 
	
	return l;
}

inline void dfs(int u) {
	vis[u] = true;
	
	int n = X.size(), m = Y.size();
	int x = u / m, y = u % m; x ++;
	if(y == 0) x --, y = m;
	int t = g[x][y];
	
	for(int i = 0; i < 4; i ++) {
		int tx = x + dx[i], ty = y + dy[i];
		if(tx < 1 || tx > n || ty < 1 || ty > m) continue;
		if(g[tx][ty] != t) continue;
		if(vis[get(tx, ty)]) continue;
		dfs(get(tx, ty));
	}
	
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	
	scanf("%d", &t);
	while(t --) {
		for(int i = 1; i <= 2; i ++) {
			scanf("%d%d%d%d", &node[i].x1, &node[i].y1, &node[i].x2, &node[i].y2);
			X.push_back(node[i].x1); X.push_back(node[i].x2);
			Y.push_back(node[i].y1); Y.push_back(node[i].y2);
		}
		
		sort(X.begin(), X.end());		
		sort(Y.begin(), Y.end());
		X.erase(unique(X.begin(), X.end()), X.end());
		Y.erase(unique(Y.begin(), Y.end()), Y.end());
		
		for(int i = 1; i <= 2; i ++) {
			int x1 = findx(node[i].x1) + 1;
			int y1 = findy(node[i].y1) + 1;
			int x2 = findx(node[i].x2) + 1;
			int y2 = findy(node[i].y2) + 1;

			for(int i = x1; i < x2; i ++)
				for(int j = y1; j < y2; j ++)
					g[i][j] += 1;

		}


//		for(int i = 1; i <= X.size(); i ++)
//			for(int j = 1; j <= Y.size(); j ++)
//				if(j == Y.size()) printf("%d\n", g[i][j]);
//				else printf("%d ", g[i][j]);
		
		int ans = 0;
		for(int i = 1; i <= X.size(); i ++)
			for(int j = 1; j <= Y.size(); j ++)
				if(!vis[get(i, j)] && g[i][j] != 0) dfs(get(i, j)), ans ++;
		
		if(ans == 1) {
			int f = 0;
			for(int i = 1; i <= X.size(); i ++) {
				for(int j = 1; j <= Y.size(); j ++) {
					if(g[i][j] == 1) {
						f = 1;
						break;
					}
				}
				if(f) break;
			}
			
			if(f) ans ++;
		}
		
		
		ans ++;
		printf("%d\n", ans);
		X.clear(); Y.clear();
		memset(g, 0, sizeof g);
		memset(vis, false, sizeof vis);
	}
	
	return 0;
} 

总结:
这道题目想到了用离散化来做就很简单,一开始我们队是直接当成几何来做,由于队友比我先看这道题,导致我都没有经过独立的思考就直接用了他们的想法导致前期花了很多时间,但方向直接就错了。下次如果说即使队友先开了一道题目,我也要想去先想一下这道题目到底想要考什么,然后再去问队友们他们解题的思路,不能盲从。如果发现有错误,一定要想清楚后,再想队友提出错误的地方。

1010:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1010&cid=855
类型:水题。
注意点:判断0.5的时候,可以直接取模,double会有精度损失。

AC代码:

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include <cmath>

using namespace std;

const int maxn = 1e5 + 10;
const double eps = 1e-4;

struct node{
	char name[15];
	int num;
	int pa;
}team[maxn];

inline int quick_sort(int l, int r, int k) {
	if(l >= r) return l;
	
	int x = team[l].num, y = team[l].pa, i = l - 1, j = r + 1;
	while(i < j) {
		do i ++; while(team[i].num < x || (team[i].num == x && team[i].pa > y));
		do j --; while(team[j].num > x || (team[j].num == x && team[j].pa < y));
		if(i < j) swap(team[i], team[j]);
	}

	int s = j - l + 1;
	if(k <= s) quick_sort(l, j, k);
	else quick_sort(j + 1, r, k - s);
}

int main(){
//	freopen("in.txt", "r", stdin);
	int t;
	scanf("%d", &t);
	while(t--){

		int n,p;
		scanf("%d%d", &n, &p);
		for(int i = 1 ; i <= n ; i ++) 
			scanf("%s%d%d", team[i].name, &team[i].num, &team[i].pa);

		int tmp = n * p;
		tmp %= 10;
		if(tmp != 5)
			printf("Quailty is very great\n");
		else {
			tmp = (int)(n * p / (10.0)) + 1;
			tmp = n + 1 - tmp;
			int s = quick_sort(1, n, tmp);
			printf("%s\n", team[s].name);
		}

	}
//	fclose(stdin);
	return 0;
}

总结:这道题目,我们当时wa了4次,这其实是完全没有必要的。下次交之前一定要把能够处理的细节都处理了再交上去,不能用评测机去当我们的判断机。(感觉当时交的时候有 些草率,可能也有些紧张的因素在里面)。

1011:http://acm.hdu.edu.cn/showproblem.php?pid=6667

题目:
Roundgod and Milk Tea
Time Limit: 6000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 688 Accepted Submission(s): 364

Problem Description
Roundgod is a famous milk tea lover at Nanjing University second to none. This year, he plans to conduct a milk tea festival. There will be n classes participating in this festival, where the ith class has ai students and will make bi cups of milk tea.

Roundgod wants more students to savor milk tea, so he stipulates that every student can taste at most one cup of milk tea. Moreover, a student can’t drink a cup of milk tea made by his class. The problem is, what is the maximum number of students who can drink milk tea?

Input
The first line of input consists of a single integer T (1≤T≤25), denoting the number of test cases.

Each test case starts with a line of a single integer n (1≤n≤106), the number of classes. For the next n lines, each containing two integers a,b (0≤a,b≤109), denoting the number of students of the class and the number of cups of milk tea made by this class, respectively.

It is guaranteed that the sum of n over all test cases does not exceed 6×106.

Output
For each test case, print the answer as a single integer in one line.

Sample Input
1
2
3 4
2 1

Sample Output
3

解题思路:
由于最后的局面一定是还剩下一个班级既有奶茶又有人,或者是全部班级的奶茶都喝完了,或者是全部班级的人都喝完了,后面2种情况是没有浪费的,所以我们需要考虑的是在第一中情况下我们怎样去分配使得剩下的人最少。
相当于说我们想要最多的人去吃掉其他班的奶茶,那么我们不妨这样想,我们让奶茶成为第一关键字,班级人数成为第二关键字,然后都是从小到大进行排序,
排完序后,我们让每次遍历到的班级的人去吃掉后面班级的奶茶;结束条件:1. 本班级的人用完了 2.后面的奶茶被吃完了。 这样的话,我们不但 可以使得本次遍历到的班级的人得到最大的利用,还能让后面的空出来能吃前面奶茶比较多的班级的奶茶。
在往后遍历的过程中,有可能会出现奶茶吃不完的情况,所以我们需要开一个pre数组来存储奶茶没吃完的班级。
在我们第一次遍历完成之后,我们在从后往前去喝奶茶,只要当前的k != i,就表示i这个班级可以吃掉前面还有剩余奶茶班级k的奶茶。
时间复杂度:排序是n * logn ,遍历是n * 2,总的时间复杂度是: O(T * n * logn)。不会超时。

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long LL;

const int maxn = 1e6 + 5;

struct Node {
	int s, t;
}node[maxn];

int t, n;
int pre[maxn];

inline bool cmp(Node a, Node b) {
	if(a.t == b.t) return a.s > b.s;
	return a.t > b.t;
}

int main(void) {
//	freopen("in.txt", "r", stdin);
	
	scanf("%d", &t);
	while(t --) {
		scanf("%d", &n);
		for(int i = 1; i <= n; i ++) scanf("%d%d", &node[i].s, &node[i].t);
		
		sort(node + 1, node + 1 + n, cmp);
		
		LL ans = 0;
		int l = 1, r = 1, f = 0;;
		for(int i = 1; i <= n; i ++) {
			if(node[i].t && i > 1) pre[i] = l, l = i;
			else if(i > 1) pre[i] = l;
			
			if(f) {
				pre[i] = l;
				continue;
			}
			if(node[i].s == 0) continue;
			//前面的人去吃后面的奶茶
			for(int j = max(r, i + 1); j <= n; j ++) {
				if(node[i].s >= node[j].t) {
					node[i].s -= node[j].t; ans += node[j].t;
					node[j].t = 0; r = j + 1;
				}
				else {
					node[j].t -= node[i].s; ans += node[i].s;
					node[i].s = 0; break;
				}	
			}
			if(node[i].s != 0) f = 1; 
			else if(node[i].s == 0 && r == n + 1) f = 1;
		}
		
		int k = n, i = n;
		if(!node[k].t) k = pre[k];

		while(k && i > 1) {
			if(node[i].s == 0) {
				i --; continue;
			}	
			
			if(k != i) {
				if(node[i].s >= node[k].t) {
					node[i].s -= node[k].t, ans += node[k].t;
					node[k].t = 0; k = pre[k];
				} else {
					node[k].t -= node[i].s, ans += node[i].s;
					node[i].s = 0; i --;
				}
			} else k = pre[k];

		}
		
		printf("%lld\n", ans);
	}
	
//	fclose(stdin);
	return 0;
}

总结:
这种做法是贪心的做法;就这道题目而言我们只要想清楚最优的情况是什么,然后分析时间复杂度是否可以过,就可以直接写了,代码中也有一些细节需要注意。
不得不说,这次训练的时候我状态没调整过来,可能也受到了前面比赛的影响没有放开,导致我在比赛时,最开始的想法错了后,思维就停止了,这点值得反省,不管什么情况下都得保持冷静!!(不能短路)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值