五一假期集训【补题】

A - Vadim’s Collection

题目来源:A - Vadim’s Collection
在这里插入图片描述
解题思路
我们可以用字符串输入这串电话号码,然后用map存每个数字的数量,然后将这十个位置一个一个放,从最大的满足10-i的数开始,通过mp值判断,如果不为空就填入这个位置,并mp–,最后得到的就是最小排列的满足条件的号码。

#include <bits/stdc++.h>
using namespace std;
map<int, int>mp;
string s;
void solve() {
	cin >> s;
	for (int i = 0; i < s.size(); i++)
		mp[s[i] - '0']++;
	int k = 1, m = 10;
	while (m--) {
		for (int i = 10 - k; i <= 9; i++) {
			if (mp[i] != 0) {
				cout << i;
				mp[i]--;
				break;
			}
		}
		k++;
	}
	cout << endl;
}

int main() {
	int t;
	cin >> t;
	while (t--)
		solve();
	return 0;
}

B - St. Chroma

题目来源:B - St. Chroma
在这里插入图片描述
在这里插入图片描述
解题思路
通过观察样例并分析规律,我们可以发现只要将格子数量最大化的数字放在最后面就可以保证它的格子数量最大化,当然要考虑一下特殊情况,就是当x>=n时,如果最后还输出x的话就不是一个排列了,因此这个时候只输出n-1的排列。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, x;

void solve() {
	cin >> n >> x;
	for (int i = 0; i < n; i++) {
		if (i != x)
			cout << i << " ";
	}
	if (x < n)
		cout << x ;
	cout << endl;
}

int main() {
	int t;
	cin >> t;
	while (t--)
		solve();
	return 0;
}

C - Bobritto Bandito

题目来源:
C - Bobritto Bandito
在这里插入图片描述
解题思路
这道题的意思就是输出一个在l,r范围内,第m天可能蔓延的区间范围,我们可以让这个区间【x,y】的起始都从0开始,每次可以先让x++,如果x=r就不能再加了,换成x–,最终输出m次后的结果即可。

#include <bits/stdc++.h>
using namespace std;
int n, m, l, r, x, y;

void solve() {
	cin >> n >> m >> l >> r;
	if (n == m) {
		cout << l << " " << r << endl;
		return;
	}
	x = 0, y = 0;
	while (m--) {
		if (y < r)
			y++;
		else
			x--;
	}
	cout << x << " " << y << endl;
}

int main() {
	int t;
	cin >> t;
	while (t--)
		solve();
	return 0;
}

D - MIN = GCD

题目来源:D - MIN = GCD
在这里插入图片描述
解题思路
可以先对这组数据进行从小到大排列,因为从最小值找更容易找到满足条件的情况,只需要让序列中的每个数对a[1]取余,如果能整除,就对上一个最大公约数再取最大公约数,直到等于a[1].

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int t, n, a[N];

void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	sort(a + 1, a + 1 + n);
	int f = 0, k = 0;
	for (int i = 2; i <= n; i++) {
		if (a[i] % a[1] == 0) {
			if (f == 1)
				k = __gcd(k, a[i]);
			else
				f = 1, k = a[i];
			if (k == a[1]) {
				cout << "YES\n";
				return ;
			}
		}
	}
	cout << "No\n";
}

signed main() {
	cin >> t;
	while (t--)
		solve();
	return 0;
}

E - Max and Mod

题目来源:E - Max and Mod
在这里插入图片描述
在这里插入图片描述
解题思路
通过找规律观察可知,

  • 当n为偶数时,无法找到满足条件的排列,因为偶数对偶数一定能将2整除,结果就是0,至少有一个位置不符合条件,输出-1即可
  • 当n为奇数时,n,1,2,...,n-1就是满足条件的排列,只要将n放在第一个,后面按字典序排列,那么n对第i个数取余一定就等于i-1,输出这个顺序的排列就可以。
#include <bits/stdc++.h>
#define int long long
using namespace std;

int t, n;

void solve() {

	cin >> n;
	if (n % 2 == 0) {
		cout << -1 << endl;
		return ;
	} else {
		cout << n << " ";
		for (int i = 1; i <= n - 1; i++)
			if (i != n - 1)
				cout << i << " ";
	}
	cout << n - 1 << " ";
	cout << endl;
}

signed main() {
	cin >> t;
	while (t--)
		solve();
	return 0;
}

F - Brogramming Contest

题目来源:F - Brogramming Contest
在这里插入图片描述
在这里插入图片描述
解题思路
这是一道简单的模拟题,找规律就行了,因为s中只能有0,t中只能有1,一开始只给了s串,我们只需要找s中有多少连续的1串,记为ans,每个连续的1串和后面连续的0串需要移动两次(将1移过去,将移过去的0移过来),同时判断最终是不是以1结尾,如果是,次数-1,因为减少了0移过来这一次,正常情况就是ans*2;

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

void solve() {
	cin >> n;
	cin >> s;
	ll k = 0;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] == '1') {
			k = i;
			break;
		}
	}
	int f1 = 0, f2 = 0;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] == '1')
			f1 = 1;
		if (s[i] == '0')
			f2 = 1;
	}
	if (!f2) {
		cout << 1 << endl;
		return ;
	}
	if (!f1) {
		cout << 0 << endl;
		return ;
	}
	ll ans = 0, sum = 0;
	if (k == 0)
		ans++;
	for (int i = k; i < s.size(); i++) {
		if (s[i] == '1' && s[i - 1] == '0') {
			ans++;
		}
	}
//	cout << ans << endl;
	if (s[s.size() - 1] == '1')
		sum = 2 * ans - 1;
	else
		sum = 2 * ans;
	cout << sum << endl;
}

int main() {
	ll t;
	cin >> t;
	while (t--)
		solve();
	return 0;
}

G - Variety is Discouraged

题目来源:G - Variety is Discouraged 在这里插入图片描述
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/abf74bb616ba4980acdd00e0f5eafdf4.png

解题思路
这道题的思路很明确,就是想能尽可能多的将只出现一次的数字删掉,这样才能满足得分尽可能的大并且a的长度尽可能小。
总而言之就是找出满足条件的最长连续子序列

  • 条件:出现次数为1,可以用map来存对应的次数。
  • 目标:找出这个序列的左端点和右端点。
  • 特殊情况:没有只出现一次的数时,不删。输出0。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, a[N];
map<int, int>mp;

void solve() {
	mp.clear();
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i], mp[a[i]]++;
	int mx = 0, ans = 0, l = 1, r = n;
	for (int i = 1; i <= n; i++) {
		if (mp[a[i]] == 1) {
			ans++;
			if (ans > mx) {
				mx = ans;
				r = i;
				l = r - ans + 1;
			}
		} else
			ans = 0;
	}
	if (mx == 0)
		cout << 0 << endl;
	else
		cout << l << " " << r << endl;
}

int main() {
	int t;
	cin >> t;
	while (t--)
		solve();
	return 0;
}

菲菲姐的游戏

题目来源:菲菲姐的游戏
在这里插入图片描述
在这里插入图片描述

解题思路
什么平均值中位数的,都是诱导你把问题想复杂的,这道题非常简单,因为是你来划分数组,那你找到最大的一个值,将你的那半数组范围包含这个最大值,如果有多个最大值,按位置靠后的最大值算,只要这个最大值的位置不在最后一个(就是=n)(因为不能有空数组),你的平均数就一定大于菲菲姐的中位数(你们都只选各自数组中最大的一个数)。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int n, k1, k2, a[N], k, mx = INT_MIN, ans = 0;
map<int, int>mp;

signed main() {

	cin >> n >> k1 >> k2;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		mp[a[i]]++;
		if (a[i] >= mx) {
			mx = a[i];
			k = i;
			ans++;
		}
	}
	if (k != n && mp.size() > 1 && ans <= k1) {
		cout << "Yes" << endl;
	} else
		cout << "No" << endl;
	return 0;
}

万年沉睡的宝藏

题目来源:万年沉睡的宝藏
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解题思路
这道题我的能力范围有限,只会单纯的用map,赛后看了下题解是让map结合set,这样更简单高效,因为可以去重,当然我还不太会用,那就给大家讲讲我的方法吧,我用了两个map,一个存对应小岛和这个小岛的这个宝藏,这两个一起存,然后记录其数量,另一个是存小岛上的宝藏种类数,为了避免重复,我们只让相应mp值=1的时候,下一个记录的值才+1,因为数量大于一后就会重复记录了,这样就避免了重复记录的问题,一开始一直错,我以为是方法不够优化,其实只是一个大括号放错了位置导致重复记录了,所以大家做题时一定要认真哦~

#include <bits/stdc++.h>
#define int long long
using namespace std;
int op, ans;
string s1, s2;
map<pair<string, string>, int>mp; //对映小岛和宝藏
map<string, int>num; //小岛上的宝藏种类数

void solve() {
//	mp.clear();
//	ans = 0;
	cin >> op;
	if (op == 1) {
		cin >> s1;
		cin >> s2;
		mp[ {s1, s2}]++;
		if (mp[{s1,s2}] == 1)
        {
        num[s1]++;
		if(num[s1]==1)
		ans++;
        }
			
	}
	if (op == 2) {
		cin >> s1;
		cout << num[s1] << endl;
	}
	if (op == 3) {
		cin >> s1 >> s2;
		if (mp[ {s1, s2}] != 0)
			cout << "1" << endl;
		else
			cout << "0" << endl;
	}
	if (op == 4)
		cout << ans << endl;
}

signed main() {

	int _;
	cin >> _;
	while (_--)
		solve();
	return 0;
}

小红的小球染色

题目来源:小红的小球染色

在这里插入图片描述
在这里插入图片描述

解题思路
因为每次要选两个小球染色,那么操作次数

  • 最大值 :两个两个的染,中间不要有空着的小球,即n/2;
  • 最小值:染两个空一个不染,一次类推,即(n-n/3)/2;
#include <bits/stdc++.h>
#define int long long
using namespace std;

signed main() {
	int n;
	cin >> n;
	int mx = n / 2;
	int mi = (n - n / 3) / 2;
	cout << mi << " " << mx << endl;
	return 0;
}

小苯的逆序对和

可看之前博客:小苯的逆序对和

小苯的蓄水池(easy)

题目来源:小苯的蓄水池(easy)
在这里插入图片描述
在这里插入图片描述
解题思路
这道题赛后看题解好像是用并查集中的find函数来做的,不过我不会呀,好在这道题的范围不大,可以直接暴力,我们可以定义一个数组表示挡板的状态(拿走或没拿走),每操作一次,我们就把L~R之间的挡板状态标记为0(已拿走),当让我们输出第i个位置的值时,我们只需要找到当前状态下i的左边第一个有挡板的位置+1,和右边第一个有挡板的位置-1,对应的这个区间的和再除以这个区间的长度,就可以得到i位置的目前值。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2005;
double a[N],sum[N];
int st[N];
signed main()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    	sum[i]=sum[i-1]+a[i];
    	st[i-1]=1;
    	st[i]=1;
	}
	while(m--)
	{
		int t;
		cin>>t;
		if(t==1)
		{
			int l,r;
			cin>>l>>r;
			for(int i=l;i<r;i++)
			st[i]=0;
		}
		else
		{
			int x;cin>>x;
			int l=x-1,r=x;
			while(l>=0)
			{
				if(st[l]==1)
				break;
				l--;
			}
			while(r<=n)
			{

				if(st[r]==1)
				break;
				r++;
			}
			printf("%lf\n",(sum[r]-sum[l])/(r-l));
		}
	}
	return 0;
}

逆序数

题目来源:逆序数
在这里插入图片描述
解题思路
这题通过找规律可以推出一个公式,直接输出就行。

以 1,2,3,4,5为例

  • k=1,可以排列为 2,1,3,4,5 逆序后的逆序对有4+3+2+1-1即(n-1)*n-k
  • k=1,可以排列为 2,3,1,4,5 逆序后的逆序对有4+3+2+1-2即(n-1)*n-k
  • k=5,可以排列为 3,2,4,5,1 逆序后的逆序对有4+3+2+1-5即(n-1)*n-k
#include <bits/stdc++.h>
#define int long long
using namespace std;

signed main() {
	int n, k;
	cin >> n >> k;
	cout << ((n * (n - 1)) / 2 - k);
	return 0;
}

雨幕

题目来源:雨幕
在这里插入图片描述

解题思路
这题范围很小,只要暴力来写就行,判断a[i][j] , a[i + 1][j] ,a[i][j + 1] ,a[i + 1][j + 1] 都为‘*’时,ans++.

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1005;
int n, m, ans;
char a[N][N];

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> a[i][j];
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (a[i][j] == '*' && a[i + 1][j] == '*' && a[i][j + 1] == '*' && a[i + 1][j + 1] == '*')
				ans++;
		}
	}
	cout << ans << endl;
	return 0;
}

不要三句号的歪

题目来源:不要三句号的歪
在这里插入图片描述
解题思路
这道题我们只需要找到第一个数和最后一个数就可以,主要是要以字符串输入

  • 1.如何将相应的字符串转化为数字?
    转化也很简单
    num=num*10+s[i]-'0'
  • 2.如何找到相应的位置进行转化
    我们可以发现第一个数字前面没有’,’ 当第一个‘,’出现时转化结束
    而最后一个数字前面有三个‘,’ 我们可以记录‘,’的数量,当数量为3时开始转化直到末尾。
  • 被省略数字的数量:最后一个数字 - 第一个数字 - 2
#include <bits/stdc++.h>
#define int long long
using namespace std;
char s[25];

signed main() {
	cin >> s;
	int x = 0, y = 0;
	for (int i = 0; i < strlen(s); i++) {
		if (s[i] == ',')
			break;
		x = x * 10 + s[i] - '0';
	}
	int ans = 0, i;
	for (int i = 0; i < strlen(s); i++) {
		if (ans == 3)
			y = y * 10 + s[i] - '0';
		if (s[i] == ',')
			ans++;
	}
	cout << y - x - 2;
	return 0;
}

降温(easy)

题目来源:降温(easy)
在这里插入图片描述
在这里插入图片描述
解题思路
妈呀,这道题太邪门了!我的思路是对的,但是写出来代码却是错的,最后改改改运行结果对了但是提交还是错的!啊太邪门了,赛后才改对,但不知道为啥这样改对。。。
好吧,还是说说思路吧!
主要是-999怎么转换才能使寒潮数量最大或最小,我们可以通过顺序遍历,当这个值等于-999时:

  • 最大
    首先判断第一个值如果是-999,让它等于最大50.
    其次是后面的值:
    如果a[i-1]-x>=-50,就让a[i]=a[i-1]-x;
    否则,还让a[i]=最大,a[i]=50.
  • 最小(可以再开一个数组,起始值与a[i]的起始值相同,方便操作)
    同样首先判断第一个值如果是-999,让它等于最小-50.
    其次是后面的值:
    如果b[i-1]-x>=-50,就让b[i]=b[i-1]-x;
    否则,还让b[i]=最小,b[i]=-50.
  • 最后就是遍历a数组和b数组了,当(a[i]-a[i-1]>=-1*x时)++。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 106;
int n, x, a[N], an1, an2, b[N];

signed main() {
	cin >> n >> x;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		b[i] = a[i];
	}
	if (a[1] == -999)
		a[1] = 50;
	for (int i = 2; i <= n; i++) {
		if (a[i] == -999) {
			if (a[i - 1] + 50 >= x)
				a[i] = a[i - 1] - x;
			else
				a[i] = 50;
		}
	}
	if (b[1] == -999)
		b[1] = -50;
	for (int i = 2; i <= n; i++) {
		if (b[i] == -999) {
			if (b[i - 1] - (x - 1) < -50)
				b[i] = -50;
			else
				b[i] = b[i - 1] - (x - 1);
		}
	}
	for (int i = 2; i <= n; i++) {
		if (a[i] - a[i - 1] <= -1 * x)
			an1++;
	}
	for (int i = 2; i <= n; i++) {
		if (b[i] - b[i - 1] <= -1 * x)
			an2++;
	}
	cout << an1 << " " << an2 << endl;
	return 0;
}

降温(hard)

题目来源:降温(hard)
在这里插入图片描述
在这里插入图片描述
解题思路
和上面同样的思路,只是将50变为500000000,-999变为-999999999

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5;
#define k 500000000
#define l -999999999
int n, x, a[N], an1, an2, b[N];

signed main() {
	cin >> n >> x;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		b[i] = a[i];
	}
	if (a[1] == l)
		a[1] = k;
	for (int i = 2; i <= n; i++) {
		if (a[i] == l) {
			if (a[i - 1] + k >= x)
				a[i] = a[i - 1] - x;
			else
				a[i] = k;
		}
	}
	if (b[1] == l)
		b[1] = -1*k;
	for (int i = 2; i <= n; i++) {
		if (b[i] == l) {
			if (b[i - 1] - (x - 1) < -k)
				b[i] = -1*k;
			else
				b[i] = b[i - 1] - (x - 1);
		}
	}
	for (int i = 2; i <= n; i++) {
		if (a[i] - a[i - 1] <= -1 * x)
			an1++;
	}
	for (int i = 2; i <= n; i++) {
		if (b[i] - b[i - 1] <= -1 * x)
			an2++;
	}
	cout << an1 << " " << an2 << endl;
	return 0;
}

总结

五一假期过得好快,快到我感受不到它的存在,虽然每天早起,一上午用来比赛,一下午用来补题,但也收获很大,不仅学会了很多东西,锻炼了自己思考的能力,提升了毅力,纠正了错误,明白了更多道理。假期当然想回家,当然想放松,但是现在做的这些都有意义,也不是孤身一人,祝大家都未来可期!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值