PTA刷题日记11

1101 Quick Sort (25 分)

只要将数组排序后lower_bound二分查找到这个元素的位置是不是和排序前在同一个位置就能过3个测试点,然后要注意有9 8 7这种序列,前后大于和小于的数正好相等,所以还需要记录一下最大值即可
一个令人无语的测试点2,一直是格式错误,就是最后要多输出一遍换行,即空一行

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int> ans;
int arr[N], a[N], ma[N];
unordered_map<int, int>mp;

int main() {
	int n;
	scanf("%d",&n);
	for(int i = 0; i < n; i++) {
		scanf("%d",a+i);
		arr[i] = a[i];
		ma[i] = max(ma[i-1], a[i]);
	}
	sort(arr, arr+n);
	for(int i = 0; i < n; i++) {
		int p = lower_bound(arr, arr+n, a[i]) - arr;
		if(p == i && a[i] == ma[i]) ans.push_back(a[i]);
	}
	printf("%d\n",ans.size());
	
	for(int i = 0; i < ans.size(); i++) {
		if(i) printf(" ");
		printf("%d",ans[i]);
	}
	printf("\n");
	return 0;
}
/*
7
1 3 2 4 7 6 8
*/

1103 Integer Factorization (30 分)

带有多重剪枝的dfs,这些剪枝要记熟,有点类似切蛋糕的题,我觉得从大到小找应该比较快(其实题目也提示了应该找从大到小的序列比较好)

剪枝情况
  1. 元素不足k个但是p次方和已经比n要大了,直接返回
  2. 后面的k-num个元素(num为当前已有的元素个数)全部取最大值仍然比n小,直接结束
  3. 提前算好结果序列最大值可能的范围
#include<bits/stdc++.h>
using namespace std;
vector<int> ans, tem;
int n, k, p, s1, s2, low, high;

int ksm(int a, int b){
	int ans = 1;
	for(; b; b >>= 1) {
		if(b&1) ans *= a;
		a *= a;
	}
	return ans;
}

void dfs(int x, int sum, int num) {
	if(num < k && sum > n) return;
	if(num == k) {
		if(sum == n && s2 > s1) {
			ans = tem;
			s1 = s2;
		}
		return;
	}
	for(int i = x; i >= 1; i--) {
		int now = ksm(i, p) ;
		if(sum + now*(k-num) < n) break;
		tem.push_back(i);
		s2 += i;
		dfs(i, sum + now, num+1);
		s2 -= i;
		tem.pop_back();
	}
}

 
int main() {
	scanf("%d %d %d",&n,&k,&p);
	high = pow(n, 1.0/p);
	low = ceil(pow(n/k, 1.0/p));
	for(int i = high; i >= low; i--) {
		tem.push_back(i);
		s2 += i;
		dfs(i, ksm(i,p), 1);
		s2 -= i;
		tem.pop_back();
	}
	if(ans.size() == k) {
		printf("%d =",n);
		for(int i = 0; i < ans.size(); i++) {
			if(i) printf(" +");
			printf(" %d^%d",ans[i],p);
		}
	}
	else printf("Impossible");
	return 0;
}

1104 Sum of Number Segments (20 分)

这题我称之为不想让你拿满分型
只有一种形式能过,就是*1000,乘100, 10000通通都是错的,还有那个double到long long的强制类型转换一定要有,否则也会错

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

int main() {
	ll n;
	scanf("%lld",&n);
	ll ans = 0;
	double t;
	for(ll i = 1; i <= n; i++ ) {
		scanf("%lf",&t);
		ans += (long long)(t * 1000) * i * (n + 1 - i);
	}
	printf("%.2f",ans/1000.0);
	return 0;
}

1106 Lowest Price in Supply Chain (25 分)

和1079几乎完全相同,同样考虑只有根节点的情况;
如果考虑剪枝就记录结点深度,记录第一个出现的叶子结点的深度,如果访问到比这个叶子结点还深的结点,直接返回,但是不剪枝也能过。。。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int> v[N];
bool isr[N];
int num;
double price[N], r, mi = 0x3f3f3f3f;

void bfs() {
	queue<int> q;
	q.push(0);
	while(q.size()) {
		int x = q.front();
		q.pop();
		for(int i = 0; i < v[x].size(); i++) {
			int y = v[x][i];
			price[y] = price[x] * r;
			if(isr[y]) {
				if(mi > price[y]) mi = price[y], num = 1;
				else if(mi == price[y]) num++;
			}
			else q.push(y);
		}
	}
}

int main() {
	int n, k, id;
	scanf("%d %lf %lf",&n, &price[0], &r);
	r = 1 + r/100;
	for(int i = 0; i < n; i++) {
		scanf("%d",&k);
		if(k) {
			while(k--) {
				scanf("%d",&id);
				v[i].push_back(id);
			}
		}
		else isr[i] = 1;
	}
	bfs();
	if(n == 1) printf("%.4lf 1",price[0]);
	else printf("%.4lf %d", mi, num);
	return 0;
}

1107 Social Clusters (30 分)

一道有点点复杂的并查集,要记录每个根的大小,我采取的办法是初始化时把每个根赋值为1,然后每次合并时把被合并的大小加到合并的根上,并且把被合并的根大小置为0,因为这个节点被合并之后在也不会作为根出现了,这样就能找出最后最终的根及大小了

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int n, fa[N], num, root[N];
vector<int> hob[N], siz;
set<int> hobby;

int find(int x) {
	if(x == fa[x]) return x;
	else return fa[x] = find(fa[x]);
}

void merge(int x, int y) {
	
	return;
}

int main() {
	scanf("%d",&n);
	num = n;
	for(int i = 1; i <= n; i++) {
		fa[i] = i;
		root[i] = 1;
	}
	for(int i = 1; i <= n; i++) {
		int q, h;
		scanf("%d:",&q);
		while(q--) {
			scanf("%d", &h);
			hob[h].push_back(i);
			hobby.insert(h);
		}
	}
	for(auto it: hobby) {
		for(int j = 0; j < hob[it].size()-1; j++) {
			int x = hob[it][j], y = hob[it][j+1];
			int fx = find(x), fy = find(y);
			if(fx != fy) {
				fa[fx] = fy;
				root[fy] += root[fx];
				root[fx] = 0;
				num--;
			}
		}
	}
	cout<<num<<endl;
	for(int i = 1;i <= n; i++) {
		if(root[i]) siz.push_back(root[i]);
	}
	sort(siz.begin(), siz.end());
	for(int i = siz.size()-1; i >= 0; i--) {
		printf("%d",siz[i]);
		if(i) printf(" ");
	}
	return 0;
}

1108 Finding Average (20 分)

测试点0应该就跟题目给的第一个输入样例一样,没什么特别的(10分)
测试点1跟题目给的第二个输入样例一样(5分)
测试点2就是输出要求的最后一句话,number不要用复数(2分)
测试点3给的小数点后有后置0(3分)
没认真审题,全部踩坑

#include<bits/stdc++.h> 
using namespace std;

double s2i(string s) {
	double n;
	stringstream ss;
	ss << s;
	ss >> n;
	return n;
}

bool islegal(string s) {
	int l = s.length();
	map<char, int> mp;
	int p = s.find('.'), i;
	if(s[0] == '-' || s[0] == '+') i = 1;
	else i = 0;
	for(; i < l; i++) {
		if(s[i] == '.' ) {
			if(mp.count('.') == 0) mp['.']++;
			else return false;
		} 
		else if(!isdigit(s[i])) return false;
	}
	for(i = l - 1; i > p; i--) {
		if(s[i] != '0') break;
	}
	if(p != string::npos && i - p > 2) return false;
	return true;
}

int main() {
	int n;
	cin >>n;
	double total = 0;
	int num = 0;
	string s;
	while(n--) {
		cin >> s;
		if(islegal(s) && s2i(s) >= -1000 && s2i(s) <= 1000) {
			num++;
			total += s2i(s);
		}
		else printf("ERROR: %s is not a legal number\n", s.c_str());
	}
	if(num > 1) printf("The average of %d numbers is %.2lf\n",num, total/num);
	else if(num == 1) printf("The average of %d number is %.2lf\n",num, total/num);
	else printf("The average of 0 numbers is Undefined\n");
	return 0;
}
/*
7
5 -3.2 003.23 1000 2.3.4 7.123 2.35
*/

1109 Group Photo (25 分)

看清题目,一开始没搞清楚k是行数,以为每一行的人数
用双端队列,将每个人按身高名字排序后依次按照题意模拟加入每一行即可

#include<bits/stdc++.h>
using namespace std;
deque<int> q[10005];
struct node{
	string name;
	int h;
	friend bool operator<(node a, node b) {
		if(a.h == b.h) return a.name < b.name;
		else return a.h > b.h;
	}
}p[10005];

int main() {
	int n, k;
	scanf("%d %d", &n, &k);
	for(int i = 0; i < n; i++) {
		cin >> p[i].name >> p[i].h;
	}
	sort(p, p+n);
	int num = n/k, rest = num + n % num, m = 0;
	for(int i = 1; i <= rest; i++) {//最后一行单独处理一下 
		if(i % 2) q[k].push_back(m);
		else q[k].push_front(m);
		m++;
	}
	for(int i = k-1; i > 0; i--) {
		for(int j = 1; j <= num; j++) {
			if(j % 2) q[i].push_back(m);
			else q[i].push_front(m);
			m++;
		}
	}
	for(int i = k; i >= 1; i--) {
		int t = 0;
		for(auto it: q[i]) {
			if(t++) printf(" ");
			cout<<p[it].name;
		}	
		cout<<endl;
	}
	
	return 0;
}

1110 Complete Binary Tree (25 分)

完全二叉树的话,我一开始想的是把结点遍历一遍只要出现下标大于n,就会出错,但这样会最后一个测试点是错的;
必须记录最大小标,只要不等于n就是出错(所以可能给我的数据不是一棵树吗,否则不可能会出现最大下标小于n的情况吧,想不通。。。)

24分代码
#include<bits/stdc++.h>
using namespace std;
bool f[55], flag, book[105];
int n;
struct node{
	int val, l, r;
}v[55];


int s2i(string s) {
	int n;
	stringstream ss;
	ss << s;
	ss >> n;
	return n;
}

int bfs(int root) {
	queue<pair<int, int> >q;
	q.push(make_pair(root, 1));
	int last;
	while(q.size()) {
		if(flag) break;
		pair<int, int> now = q.front();
		last = now.first;
		q.pop();
		int ind1 = now.second * 2, ind2 = ind1 + 1;
		if(v[last].l != -1) {
			if(ind1 > n) flag = 1;
			else q.push(make_pair(v[last].l, ind1));
		}
		if(v[last].r != -1) {
			if(ind2 > n) flag = 1;
			else q.push(make_pair(v[last].r, ind2));
		} 
	}
	return last;
}

int main() {
	string l, r;
	scanf("%d",&n);
	for(int i = 0; i < n; i++) {
		cin >> l >> r;
		if(l == "-") {
			if(r == "-") v[i].l = v[i].r = -1;
			else flag = 1;
		}
		else {
			v[i].l = s2i(l), f[v[i].l] = 1;
			if(r == "-") v[i].r = -1;
			else v[i].r = s2i(r), f[v[i].r] = 1;
		}
	}
	int root;
	for(int i = 0; i < n; i++) {
		if(!f[i]) {
			root = i;
			break;
		}
	}
	int last = bfs(root);
	if(flag) printf("NO %d",root);
	else {
		printf("YES %d",last);
	}
	return 0;
}
ac代码
#include<bits/stdc++.h>
using namespace std;
bool f[55], flag = 0;
int n, maxInd;
struct node{
	int val, l, r;
}v[55];

int s2i(string s) {
	int n;
	stringstream ss;
	ss << s;
	ss >> n;
	return n;
}

int bfs(int root) {
	queue<pair<int, int> >q;
	q.push(make_pair(root, 1));
	int last;
	while(q.size()) {
		pair<int, int> now = q.front();
		q.pop();
		last = now.first;
		maxInd = max(maxInd, now.second);
		int ind1 = now.second * 2, ind2 = ind1 + 1;
		if(v[last].l != -1) {
			q.push(make_pair(v[last].l, ind1));
		}
		if(v[last].r != -1) {
			q.push(make_pair(v[last].r, ind2));
		} 
	}
	return last;
}

int main() {
	string l, r;
	cin >> n;
	for(int i = 0; i < n; i++) {
		cin >> l >> r;
		if(l == "-") v[i].l = -1;
		else v[i].l = s2i(l), f[v[i].l] = 1;
		if(r == "-") v[i].r = -1;
		else v[i].r = s2i(r), f[v[i].r] = 1;
	}
	int root;
	for(int i = 0; i < n; i++) {
		if(!f[i]) {
			root = i;
			break;
		}
	}
	int last = bfs(root);
	if(maxInd != n) printf("NO %d",root);
	else {
		printf("YES %d",last);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值