[2021CSP-J]模拟赛#2总结

T1

原题戳这里
分值 100
一道简单的结构体排序题,开一个结构体,为时,分,秒,然后按时,分,秒的顺序从小到大sort一遍。
当时老刘在钉钉@所有人T1的范围出锅了 n<=5000。
辛好我看了一眼钉钉不然20分又没了。

const int maxn=1e6;
struct time
{
	int h,m,s;
}a[maxn];
bool my_sort(time x,time y)
{
	if(x.h==y.h&&x.m!=y.m) return x.m<y.m;
	//如果x的小时和y的小时一样且x的分钟不等于y的分钟就按分钟从大到小排序。
	else if(x.h==y.h&&x.m==y.m) return x.s<y.s;
	//如果x的小时和y的小时一样且x的分钟等于y的分钟就按小时从大到小排序。
	else  return x.h<y.h;
	//如果上面的都不是就按秒数排序。
}
//------分割线--------
//你还可以这样写
bool my_sort(time x,time y)
{
	if(x.h==y.h)
	{
		if(x.m==y.m)
		{
			return x.s<y.s;
		}
		return x.m<y.m;
	}
}

时间复杂度 O(nlogn)
满分直接拿下,AC。

T2

原题戳这里
20分
第二题是一道比较绕的贪心,其实在考场上想的也是贪心但贪的策略错了,只拿到了20分,接下来看题解。

20tps

就一个普通的贪心,如果他明天的食物够吃,今天就锻炼,如果不够就去采摘

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7;
long long sb = 0;
int a[maxn];
int main()
{
	bool flag = false;
	long long n,m,x;
	cin >> n;//输入有几组数据
	for (int i = 1; i <= n; i++)
	{
			cin >> m >> x;//输入他留这的天数,和他初始的体力值
		for (int j = 1; j <= m; j++)
		{
			cin >> a[j];//输入每天要吃的食物
		}
		for (int k = 1; k <= m; k++)
		{
			if (sb < 0)//如果他即使是采之后还不够吃就输出-1。
			{
				cout << "-1" << endl;
				flag = true;//标记为true。
				break;//跳出
			}
			if (sb < a[k]) sb += x;//如果他小于了他要吃的食物就去采摘。
			else x++;//如果够就去锻炼。
			sb -= a[k];//食物就减去他吃的。
		}
		if(!flag) cout << sb << endl;//如果他挺过了m天就输出。
	}
	return 0;
}

100 pts

我们应该前期提升能力,后期采集⻝物,要保持均衡但是怎么保持均衡呢?
假设现在为第 i 天,如果第 i 天选择提升能⼒,那么可以增加采集⻝物的量为 n-i。因为 n-i 天的采集数量为1。怎么保证均衡,如果当前第 i 天采集⻝物的能⼒,为X-i 时,再提升 X,只会让采集⻝物的量减少。下面看代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7;
int sb = 0, num = 0;
bool flag = false;
long long a[maxn];
int main()
{
	char ch;
	int len, t;
	int x;
	long long num = 0;
	cin >> t;//有t组测试数据
	while (t--)
	{
		long long n, l;
		long long sum = 0;
		long long add = 0;
		cin >> n >> l;//输入他带的天数,和初始的体力
		for (int i = 1; i <= n && sum != -1; ++i)
		{
			cin >> x;//输入他这天吃的食物量
			if (sum < x)//如果他的剩得食物小与他今天吃的。
			{
				sum += add + l;
				while (sum < x && add>0 && (add + l - 1) > i - a[add])
				{
					sum = sum + add + l - 1 - (i - a[add]);
					add--;
				}
				if (sum < x) sum--;
				else sum -= x;
			}
			else//如果够
			{
				if (n - i > add + l) a[++add] = i;
				else sum += add + l;
				sum -= x;
			}
		}
		cout << sum << endl;//输出。
	}
	return 0;
}

时间复杂度O(nx)

T3

原题戳这里
80分
数组开小了,这道题就是模拟题将感染者和未感染着的基因序列进行比对如果他们之间出现了没有出现的基因计数器就加加,下面看代码。
没想到他数据真有200我吐了呀

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
const int minn=250;
int sb = 0, num = 0;
char a[maxn],b[maxn];
char s[minn][minn];
int main()
{
	bool flag = false;
	long long n,m,x;
	cin >> n >>x;//输入这个序列的长和有多少个人
	for (int i = 1; i <= n*2; i++)//输入每个人的基因序列
	{
		for (int j = 1; j <= x; j++)
		{
			cin >> s[i][j];
		}
	}
	for (int j = 1; j <= x; j++)//将他们一一对比
	{
		for (int i = 1; i <= n; i++)//把为感染的人的第i列基因序列取出来
		{
			b[i] = s[i][j];
		}
		sb = 0;
		for (int k = n+1; k <= n*2; k++)//吧感染者的第k列基因取出来
		{
			a[++sb] = s[k][j];
		}
		for (int i = 1; i <= n; i++)//进行一一比对。
		{
			for (int j = 1; j <= n; j++)
			{
				if (a[i] == b[j])//如果有一个相同的就把flag标为true,break。
				{
					flag = true;
					break;
				}
			}
			if (flag) break;//如果为true就break。
		}
		if (!flag) num++;//如果不同的话计数器加加
		flag = false;//将flag重新标记为flase。
		sb = 0;//a数组的位数重新清为零。
	}
	cout << num;//输出有几个不相同的
	return 0;
}

时间复杂度 O(2n*x)
这个题还有另一种写法就是开一个桶看看有没有单个的有就加加,代码就不展示了。

T4

原题戳这里
0分
提上说50%的数据每次查寻为[1…107]所以我没可以枚举25次然后去O(1)查询。
100%的数据高达[1…1018]我当时还以为他数据出锅了呢,最后就写了一个50分的,但我忘删调试代码了,hhh苦笑

50pts

#include<bits/stdc++.h>
using namespace std;
int sb = 0, num = 0;
int main()
{
	bool flag = false;
	long long n, m, x;
	string s, s1;
	cin >> s;//输入初始字符串
	cin >> n;//输入n组数据
	s1 = s;
	for (int i = 1; i <= 21; i++)//预处理出这个字符串进行25次操作后的字符
	{
		char s2 = s[s.size() - 1];//让s2等于s串的最后一个字符
		for (int j = s.size() - 1; j >= 0; j--)//倒着项后移一位
		{
			s[j + 1] = s[j];//把钱面那个得到他的后面那个。
		}
		s[0] = s2;//将最后一位移到第一位
		s1 += s;//将转化后的字符串和原来的字符串连接到一起。
		s = s1;
	}
	for (int i = 1; i <= n; i++)
	{
		cin >> m;//输入查询第几位
		cout << s1[m-1] << endl;//O(1)查询是第多少个
	}
	return 0;
}

100 pts

其实这道题是经典的分治,通过观察我们可以发现,每⼀次 增⻓的部分 的第⼀位跟原部分的最后⼀位相同,增⻓部分的第⼆位到最后⼀位跟原部分的第⼀位到倒数第⼆位相同。
观察样例: ABC 拓展为 AB C C AB 继续拓展 ABCCA B B ABCCA
所以是不是有点像肉夹馍那道题(不知道的戳这里)
code

#include<bits/stdc++.h>
using namespace std;
int sb = 0, num = 0;
char a[100000001];
int main()
{
	char ch;
	long long len, t;
	int n;
	long long num = 0;
	string s;
	cin >> s;//输入初始的子串
	cin >> n;//输入查询几次
	while (n--)
	{
		len = s.size();//让len等于当前s的长度。
		cin >> t;//输入他查询的位置
		while (t> len)//如果他输的数大于了s串的长度,要开始拓展
		{
			long long p = len;//让p等于s串的长度
			while (t > p * 2) { p =p*2; }//如果这个查询的数还大于串的长度就继续扩展
			t =t-(p + 1);//用查询的长度减串的长度。
			if (t == 0)//如果看好减完就证明t的查询和p的长度一样
			{
				t = p;
			}
		}
		cout << s[t-1]<<endl;//输出他的字母。
	}
	return 0;
}

T5(不会)

听说老刘说这道题是防AK的是一道动态规划题但dalao——klz大佬用bfs给他AC了%%%%%%,但钊哥的BFS真不是盖的,有某人说这不是有手就行,好吧我没有手

总结

本次一共的分数为 100+20+80+0+0=200。
期望的分 100+80+100+50+0=330。
相差的有点大,有点可惜,在过程中也是无比的的紧张,而且中间还出了亿点小状况,但也还可以吧。
祝各位Oier七夕节快乐。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值