pair + sort + 栈 2018-6-17 ACM 刷题日记

<Codeforces 988E>   思维

题意:

给一个数,在这个数的各个数位中只能进行它相邻两位的互换,问最少经过经过多少次如上操作让这个数能被25整除。

思路:

由于被25整除的数都有一个性质,那就是末两位只能是25,50,75,00。所以我的想法是,构造一个后缀ab,看ab是不是以上四种中的某几种,比如2057,它能构成三种后缀,即25,50,75,显然75是花费最小的那种。于是我就写了一个子函数solve如下,各变量和操作注释得较详细,这里不再详述:

int solve(char a, char b) {
	string t;
	t = s;
	int ln = t.length();
	bool flg1 = 0, flg2 = 0; //判断能否构成后缀
	int cnt = 0; //计算构成后缀ab的移动步数

	for(int i = ln - 1; i >= 0; i--) { //将最后一位字符置为b
		if(t[i] == b) {
			flg1 = 1;
			for(int j = i; j < ln - 1; j++) {
				swap(t[j], t[j + 1]);
				cnt++;
			}
			break;
		}
	}

	for(int i = ln - 2; i >= 0; i--) { //将倒数第二位字符置为a
		if(t[i] == a) {
			flg2 = 1;
			for(int j = i; j < ln - 2; j++) {
				swap(t[j], t[j + 1]);
				cnt++;
			}
			break;
		}
	}

	bool chk = 0; //判断能否满足题意
	if(flg1 && flg2) { //能构成后缀ab, 处理前导0
		if(t[0] != '0') chk = 1; 
		else {
			for(int i = 1; i < ln - 2; i++) {
				if(t[i] != '0') {
					cnt += i;
					chk = 1;
					break;
				}
			}
		}
	}
	if(chk) return cnt;
	else return -1;
}

然后用solve加工四个后缀,看有哪几种能被构成,这里需要注意一个问题,如果这个数本身就能被25整除,我写的solve就会返回-1,所以就单独判一下输出0就行了。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7;
const int Inf = 1e9 + 7;
string s;

int solve(char a, char b) {
	string t;
	t = s;
	int ln = t.length();
	bool flg1 = 0, flg2 = 0; //判断能否构成后缀
	int cnt = 0; //计算构成后缀ab的移动步数

	for(int i = ln - 1; i >= 0; i--) { //将最后一位字符置为b
		if(t[i] == b) {
			flg1 = 1;
			for(int j = i; j < ln - 1; j++) {
				swap(t[j], t[j + 1]);
				cnt++;
			}
			break;
		}
	}

	for(int i = ln - 2; i >= 0; i--) { //将倒数第二位字符置为a
		if(t[i] == a) {
			flg2 = 1;
			for(int j = i; j < ln - 2; j++) {
				swap(t[j], t[j + 1]);
				cnt++;
			}
			break;
		}
	}

	bool chk = 0; //判断能否满足题意
	if(flg1 && flg2) { //能构成后缀ab, 处理前导0
		if(t[0] != '0') chk = 1; 
		else {
			for(int i = 1; i < ln - 2; i++) {
				if(t[i] != '0') {
					cnt += i;
					chk = 1;
					break;
				}
			}
		}
	}
	if(chk) return cnt;
	else return -1;
}

int main() {
	cin >> s;
	int l = s.length();
	ll sum = 0;
	ll tmp = 1;
	for(int i = l - 1; i >= 0; i--) {
		sum += (s[i] - '0') * tmp;
		tmp *= 10;
	}
	if(sum % 25 == 0) {
		puts("0"); return 0;
	}

	int minT = Inf;
	int r1 = solve('2', '5');
	if(r1 != -1) minT = min(r1, minT);

	int r2 = solve('5', '0');
	if(r2 != -1) minT = min(r2, minT);

	int r3 = solve('7', '5');
	if(r3 != -1) minT = min(r3, minT);

	int r4 = solve('0', '0');
	if(r4 != -1) minT = min(r4, minT);
	//cout << r1 << " " << r2 << " " << r3 << " " << r4 << endl;

	if(minT == Inf) puts("-1");
	else cout << minT <<endl;
}

<Codeforces 982B>

 

题意:

一辆车上有n排座位,每排有一个座位,且每排座位长度互不相同,规定每排座位上能且只能坐两个人,

上车的有A,B两类人,

A:只挑 没人的 且座位长度小的 座位坐; B:只挑 有人的 且座位长度大的 座位坐

输入一个长度为2 * n 的 01串,0代表A类人,1代表B类人,问根据这个01串输出这2 * n个人坐在了哪排的座位,保证输入样例完全合法。

思路:

根据这些人的上车顺序可知,B类人都是和A类人坐在一起的,即AB捆绑,不存在B和B坐在一起这种情况,即会出现 n 对捆绑的 AB 分别坐在这 n 排上。首先根据两类人上车的顺序,再加上AB捆绑,就特别容易想到栈和队列,这里我采用 栈模拟 的手段。

先定义一个 pair,不必紧张,我也是做这题现学的pair,我来讲下 pair 的作用。

声明方式:pair <int, int> A[maxn];

是不是和 map 有点像 ~?没错,map <int, int> mp,表示两个关联的属性,输入一个a[i],对应出一个 mp[ a[i] ],因此map又叫做关联数组,即mp[ a[i] ] 与 a[i] 关联。pair 其实也是同理,pair 有两个属性,first 和 second,和map不同的是,pair 的first 和 second是针对同一个数组的两个属性。打个比方,有4张桌子,first表示桌子长度,second表示桌子宽度,first 和 second 都是桌子这个对象的属性;而 map 是这样子的一个存在,有四张桌子,记为a[1] ~ a[4],对于a[1] ~ a[4],每张桌子的价格记为 mp[a[1]] ~ mp[a[4]]。这样是不是就理解了很多 ~ 由于pair是针对同一对象的两个属性,就可以将pair类比为结构体来理解。

介绍完pair,说一下针对pair的排序,直接sort的话,就相当于按照默认状态排序,(与结构体排序不同的是,不必声明cmp再在sort中调用)而这个默认状态就是按照first属性升序排列,如果first属性相等就按照second属性升序排。

所以思路就构造出来了,先按身为first属性的椅子长度升序排,由于样例合法,先上来的肯定是A类人,即01串开头一定是0,初始状态车上没人,所以这个最先上来的A类人,一定去找椅子长度最短的座位坐,这也是升序排的理由,然后他坐下以后,就直接打印这排编号就行了,即second属性,然后压进栈,接下来如果上来的是A,那就重复以上操作,如果是B,由于栈后进先出,故此时栈顶就是目前被A坐着的,长度最长的椅子的编号,打印编号,捆绑出栈即可。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <ctime>
#include <cctype>
#include <queue>
#include <stack>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
const int Inf = 1e9 + 7;
queue <int> qua;
set <int> sst;
vector <int> vect;
map <int, int> mp;
priority_queue < int, vector<int>, less<int> > qua1;
priority_queue < int, vector<int>, greater<int> > qua2;

int n;
string s;
pair <int, int> A[maxn];
stack <int> stk;

int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> A[i].first; //first表示椅子长度
		A[i].second = i; //second表示第几排
	}

	cin >> s;
	int l = s.length();
	sort(A + 1, A + n + 1); //默认按first升序排

	int pos = 1;
	for(int i = 0; i < l; i++) {
		if(s[i] == '0') {
			cout << A[pos].second << " ";
			stk.push(A[pos].second);
			pos++; //角标后移, 因为内向的人要找没人的座位就坐
		}
		else {
			cout << stk.top() << " "; //由于栈后进先出, 故栈顶此时就是目前栈内长度最长的那个椅子编号
			stk.pop(); //匹配后出栈
		}
	}
	cout << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章