2021第六届GPLT 团体程序设计天梯赛CCCC 个人题解

L1-1 人与神

Code

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

const int N = 10005;

int main()
{
	puts("To iterate is human, to recurse divine.");
	return 0;
}

L1-2 两小时学完C语言

Code

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

int main()
{
	ll n,k,m;
    cin>>n>>k>>m;
    if(k * m >= n) puts("0");
    else printf("%lld\n",n-k*m);
	return 0;
}

L1-3 强迫症

思路

输入就两种可能,1.长度为4  2.长度为6,分类讨论一下就好了

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
	string ch;
	cin>>ch;
	if(ch.size() ==  6) {
		for(int i = 0;i < 4; ++i) {
			putchar(ch[i]);
		}
		putchar('-');
		putchar(ch[4]);
		putchar(ch[5]);
	}
	else {
		int k = (ch[0]-'0')*10 + (ch[1]-'0');
		if(k < 22) {
			printf("20");
			
		}
		else
			printf("19");
		putchar(ch[0]);
			putchar(ch[1]);
			putchar('-');
			putchar(ch[2]);
			putchar(ch[3]);
	}
	return 0;
}

L1-4 降价提醒机器人

Code

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

const int N = 10005;

int main()
{
	int n;
	double m,k;
	scanf("%d%lf",&n,&m);
	for(int i = 1;i <= n; ++i) {
		scanf("%lf",&k);
		if(k < m) {
			printf("On Sale! %.1lf\n",k);
		}
	}
	return 0;
}

L1-5 大笨钟的心情

思路

直接模拟就好了,注意的是输入不在[0,23]的话,就结束,而不是输入-1才结束

Code

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

const int N = 10005;

int a[25];

int main()
{
	for(int i = 0;i < 24; ++i) {
		scanf("%d",&a[i]);
	}
	int k;
	while(~scanf("%d",&k)) {
		if(k < 0 || k > 23)
			break;
		if(a[k] > 50) {
			printf("%d Yes\n",a[k]);
		}
		else
			printf("%d No\n",a[k]);
	}
	return 0;
}

L1-6 吉老师的回归

解题思路

注意的是这里吉老师遇到qiandao或者easy的话是不算作吉老师当前完成的题目里面去的,我们先将吉老师做完的题目数进行消耗,然后后面出来输入的第一个不包含easy或者qiandao的字符串就是吉老师当前做的题目,但是如果题目数已经用完了,那就说明吉老师AK了

Code

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

char *str[2]={"easy","qiandao"};


bool find(string ch) {//暴力匹配
	int len = ch.size();
	for(int i = 0;i < len; ++i) {
		bool fg = true;
		if(ch[i] == 'e' && i + 3 < len) {
			for(int j = 0;j < 4; ++j) {
				if(str[0][j] != ch[i+j]) {
					fg = false;
					break;
				}
			}
			if(fg)
			return fg;
		}
		else if(ch[i] == 'q' && i + 6 < len) {
			for(int j = 0;j < 7; ++j) {
				if(str[1][j] != ch[i+j]) {
					fg = false;
					break;
				}
			}
			if(fg)
			return fg;
		}
	}
	return false;
}

int main()
{
	string ch;
	int n,m;
	cin>>n>>m;
	getchar();
	int loc = 0;
	while(m && loc < n) {
		getline(cin,ch);
		loc++;
		if(find(ch)) continue;
		m--;
	}
	
	while(loc < n) {
		getline(cin,ch);
		loc++;
		if(find(ch)) continue;
		string temp;
		while(loc < n)  getline(cin,temp),loc++;//将未输入完的字符串先输入
		cout<<ch<<"\n";
		return 0;
	}
	puts("Wo AK le");
	
	return 0;
}

L1-7 天梯赛的善良

解题思路

我们用两个变量分别记录参赛学生的最小能力值以及参赛学生的最大能力值,然后再用两个变量记录最小和最大的数目,最后遍历一遍即可得到答案

Code

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 100005;

int a[N];

int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 0;i < n; ++i) {
		scanf("%d",&a[i]);
	}
	int max_k = -1;
	int max_loc = 0;
	int min_k = INF;
	int min_loc = 0;
	for(int i = 0;i < n; ++i) {
		if(a[i] > max_k) {
			max_k = a[i];
		}
		if(a[i] < min_k) {
			min_k = a[i];
		}
	}
	for(int i = 0;i < n; ++i) {
		if(a[i] == max_k) {
			max_loc++;
		}
		if(a[i] == min_k) {
			min_loc++;
		}
	}
	printf("%d %d\n%d %d\n",min_k,min_loc,max_k,max_loc);
	return 0;
}

L1-8 乘法口诀数列

解题思路

直接模拟,开一个vector存储当前得到的整数,然后操作n次,最后输出前n个数字即可

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int N = 100005;

int a[N];

int main()
{
	ll a,b,n;
	scanf("%lld%lld%lld",&a,&b,&n);
	vector<int> V;
	V.push_back(a);
	V.push_back(b);
	
	for(int i = 0;i <= n; ++i) {
		ll k = V[i] * V[i+1];
		stack<int> S;
		while(S.size()) S.pop();
		if(k == 0) V.push_back(0);
		while(k) {
			S.push(k % 10);
			k /= 10;
		}
		while(S.size()) {
			V.push_back(S.top());
			S.pop();
		}
	}
	for(int i = 0;i < n; ++i) {
		printf("%d%c",V[i],i == n-1?'\n':' ');
	}
	return 0;
}

L2-1 包装机

解题思路

我们将每条轨道看成一个队列,然后将筐看成栈,再把流水线看成队列,这不就是很简单的队列和栈的操作嘛,0操作也就是出栈,入队操作,-1表示的是结束操作,其他数字表示的是队列出队然后入栈操作,只不过注意的是这里的栈是有大小限制的,超过栈的大小,强制出栈,入流水线队列,然后再入栈

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,s;

const int N = 1005;

queue<int> que[N];
stack<int> S;
vector<char> ans;
int main()
{
	cin>>n>>m>>s;
	string ch;
	getchar();
	for(int i = 1;i <= n; ++i) {
		getline(cin,ch);
		for(int j = 0;j < m; ++j) {
			que[i].push(ch[j]);
		}
	}
	int k;
	while(cin>>k) {
		if(k < -1 || k > n) continue;
		if(k == - 1) {
			for(int i = 0;i < ans.size(); ++i) {
				putchar(ans[i]);
			}
			putchar('\n');
			break;
		}
		if(k == 0) {
			if(S.size()) {
				ans.push_back(S.top());
				S.pop();
			}
		}
		else {
			if(que[k].size()) {
				if(S.size() >= s) {
					ans.push_back(S.top());
					S.pop();
				}
				S.push(que[k].front());
				que[k].pop();
			}
		}
	}
	
	return 0;
}

L2-2 病毒溯源

解题思路

一个母体病毒株能变异出k个子病毒,这不就是我们熟悉的树形结构嘛,然后题目问病毒的最长变异链,如果相同则输出序列小的那一种,我们很明显能想到并查集这种数据结构,(注意不要压缩路径),我们完成建树后,先找到最长变异链的长度,然后将所有最长变异链放在vector[]里面,最后再对这个vector进行排序输出vector[0]的变异链即可

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,s;

const int N = 100005;

int fa[N];
int cnt[N];

vector<int> V[N];

void init(int n) {
	for(int i = 1;i <= n; ++i) {
		fa[i] = i;
	}
}

inline int find(int x) {
	while(x != fa[x]) x = fa[x];
	return x;
}
inline int get_size(int x) {
	int ans = 1;
	while(x != fa[x]) x = fa[x],ans++;
	return ans;
}

inline void merge(int a,int b) {
	if(a != b) {
		fa[b] = a;
	}
}

bool cmp(vector<int> a,vector<int> b) {
	int len = a.size();
	for(int i = 0;i < len; ++i) {
		if(a[i] == b[i]) continue;
		return a[i] < b[i];
	}
}
stack<int> ans;
int main()
{
	cin>>n;
	init(n);
	int k;
	for(int i = 1;i <= n; ++i) {
		cin>>k;
		int t;
		for(int j = 0;j < k; ++j) {
			cin>>t;
			t++;
			merge(i,t);
		}
	}
	int len = 1;
	for(int i = 1;i <= n; ++i) {
		cnt[i] = get_size(i);
		len = max(len,cnt[i]);
	}
	int LL = 0;
	for(int i = 1;i <= n; ++i) {
		if(cnt[i] == len) {
			k = i;
			while(fa[k] != k) {
				ans.push(k);
				k = fa[k];
			}
			ans.push(k);
			while(ans.size()) {
				V[LL].push_back(ans.top());
				ans.pop();
			}
			LL++;
		}
	}
	sort(V,V + LL);
	int L = V[0].size();
	printf("%d\n",L);
	for(int i = 0;i < L; ++i) {
		printf("%d%c",V[0][i] - 1,i == L - 1?'\n':' ');
	}
	return 0;
}

L2-3 清点代码库

解题思路

我们可以直接用map的键存储这一行数据,然后再开一个结构体的vector存储的是map的键与值,最后自己写一下sort的排序方式,即先按照数据存在的次数从大到小,最后再按照字典序排序,这里有个坑点,就是不要将一行数据看成一个字符串,这样你后面排序的时候会出问题,因为每个元素的长度不一定相同,字符串匹配可能匹配到 ‘ ’空格(别问我怎么知道的T_T),详情请看代码

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int N = 100005;

map<vector<int>,int> vis;
struct Node {
	vector<int> V;
	int cnt = 0;
};

bool cmp(Node a, Node b) {
		if(a.cnt == b.cnt) {
			int len = a.V.size();
			for(int i = 0;i < len; ++i) {
				if(a.V[i] == b.V[i]) continue;
				return a.V[i] < b.V[i]; 
			}
		}
		return a.cnt > b.cnt;
}
int n,m;

int main()
{
	scanf("%d%d",&n,&m);
	vector<int> temp;
	for(int i = 0;i < n; ++i) {
		temp.clear();
		int t;
		for(int j = 0;j < m; ++j) {
			scanf("%d",&t);
			temp.push_back(t);
		}
		vis[temp] ++;
	}
	int len = vis.size();
	vector<Node> a;
	for(auto it : vis) {
		Node temp;
		temp.cnt = it.second;
		temp.V = it.first;
		a.push_back(temp);
	}
	sort(a.begin(),a.end(),cmp);
	printf("%d\n",len);
	for(int i = 0;i < len; ++i) {
		printf("%d ",a[i].cnt);
		for(int j = 0;j < m; ++j) {
			printf("%d%c",a[i].V[j],j==m-1?'\n':' ');
		}
	}
	
}

L2-4 哲哲打游戏

解题思路

因为有n行剧情点,所以我们用一个vector数组V[N]来存储这些剧情,因为我们有存档的操作,并且档案数不超过100,我们可一个开一个大小为105的数组来表示,也可以开一个map来表示档案,我们用loc表示当前哲哲在哪个剧情点(最开始为1),m次操作,每次操作有三种情况,0操作表示的在当前剧情点选择第j个剧情,loc也要跳转,1操作表示的是将当前loc位置的档案存在j位置上,2表示的是读档,此时loc要跳转到读档的位置去(就一个很简单的模拟题啊~)

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
const int N = 100005;

int n,m;

vector<int> V[N];
map<int,int> dangan;

int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n; ++i) {
		int k,kk;
		scanf("%d",&k);
		for(int j = 1;j <= k; ++j) {
			scanf("%d",&kk);
			V[i].push_back(kk);
		}
	}
	int u,v;
	int loc = 1; 
	int len = 1;
	for(int i = 1;i <= m; ++i) {
		scanf("%d%d",&u,&v);
		if(u == 0) {
			loc = V[loc][v-1];
		}
		else if(u == 1) {
			printf("%d\n",loc);
			dangan[v] = loc;
		}
		else if(u == 2) {
			if(dangan[v])
			 	loc = dangan[v];
		}
	}
	printf("%d\n",loc);
}

L3-2 还原文件

解题思路

因为答案是唯一的,所以我们对每一个小碎片进行暴力匹配(这样能骗26分),测试点二会T

Code

26分代码

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

const int N = 100005;
int a[N];
vector<int> V[N];
int key[N];

int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n; ++i) {
		scanf("%d",&a[i]);
	}
	int k,t;
	scanf("%d",&m);
	int loc = 1;
	for(int i = 1;i <= m; ++i) {
		scanf("%d",&k);
		for(int j = 1;j <= k; ++j) {
			scanf("%d",&t);
			V[i].push_back(t);
		}
	}
	int ans = 1;
	int kk = 1;
	while(1) {
		for(int i = 1;i <= m; ++i) {
			if(V[i][0] == a[loc]) {
				int len = V[i].size();
				if(loc + len <= n) {
					bool fg = true;
					for(int j = 0;j < len; ++j) {
						if(a[loc+j] != V[i][j]) {
							fg = false;
							break;
						}
					}
					if(fg) {
						key[ans] = i;
						ans++;
						loc += len-1;
						break;
					}
				}
			}
		}
		if(ans == m) break;
	}
	map<int,bool> vis;
	for(int i = 1;i < m; ++i) {
		printf("%d ",key[i]);
		vis[key[i]] = true;
	}
	for(int i = 1;i <= m; ++i) {
		if(!vis[i])  {
			printf("%d\n",i);
			break;
		}
	}
	return 0;
}

/*

17
95 70 80 97 97 68 58 58 80 72 88 81 81 68 68 60 80
6
4 68 58 58 80
3 81 68 68
3 95 70 80
3 68 60 80
5 80 72 88 81 81
4 80 97 97 68
*/

最后

222分国二滚粗,L2-3死活有个点T了,当时没想到用vector作为map键优化,想到了用string作为map的键,结果排序的时候搞炸了,比赛体验总体还不错,希望下次能国一(
祝大家都能拿到理想的成绩

posted @ 2021-04-26 13:53  MangataTS  阅读(459)  评论(0编辑  收藏  举报