Codeforces Round 799 (Div. 4)题解ABCDEFGH

A. Marathon

题意:四个人在马拉松比赛中分别跑了 a,b,c,d 米,保证四个数两两不同,问比第一个人(跑 a 米的那个)跑得更远的人有几个。

思路:模拟即可

	int a, b , c , d;
	cin >>a >> b >>c >>d;
	int cnt = 0;
	if(b >a)cnt++;
	if(c >a)cnt++;
	if(d >a)cnt ++;
	cout <<cnt << endl;

B. All Distinct

题意:有多组数据。 给你若干个数,每次删除 2 个数,求删除若干次后使数中没有重复的前提下剩下最长的长度

思路:题意比较抽象,可以理解为:每次操作可以删除两个数,求经过任意次操作后,剩下的序列没有相同的元素,求剩下的序列的最长的长度

我们可以发现,每次会删除两个数,最后剩下两种情况:

1:还剩一对相同的

2:一对不剩

然后记录一下能删除多少,模拟即可

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		vector<int> a(n);
		map<int,int> mp;
		for(int i = 0;i<n;i++){
			cin >>a[i];
			mp[a[i]]++;
		}
		int cnt = 0;
		for(auto [k,v] : mp){
			if(v > 1){
				cnt += v - 1;
			}
		}
		if(cnt % 2 &  1)cout << sz(mp) - 1 << endl;
		else cout << sz(mp) << endl;
	}

C. Where's the Bishop?

题意:

有一个8×8的棋盘,列编号从左到右递增,行编号从上到下递增。

给出一个棋盘,上面用#标明了主教的攻击范围。请你找出主教的位置坐标,并输出其行、列编号。

保证:主教的行、列编号均在2与7之间。

思路:明显要符合国际象棋象的走法,左上右上左下右下都要是#,模拟即可

    string c[10];
	for(int i=0;i<8;++i) cin>>c[i];
	for(int i=1;i<7;++i){//遍历数组
		for(int j=1;j<7;++j){
			if(c[i][j]=='#'&&c[i-1][j-1]=='#'&&c[i-1][j+1]=='#'&&c[i+1][j-1]=='#'&&c[i+1][j+1]=='#'){
				cout<<i+1<<" "<<j+1<<"\n";
				return;
			}
		}
	}

D. The Clock

题意:

从一个24小时制的时间点开始,每隔 x 分钟看一次手表,求到重新看到此时间点为止一共看到了多少个回文时间点。

回文时间点:诸如13:31,25:52等时间点。

思路:我们可以发现过了 3600 次 x 秒后,当前的时间就一定与原来输入的时间一致,形成循环。

因此枚举每一个可能的时间,判断即可。

    int t;
    int sh,sm,x;
	cin >> t;
	while(t--){
		scanf("%2d:%2d\n",&sh,&sm);
		cin >> x;
		int nh=sh,nm=sm;
		int ans=0;
		for(int i=1;i<=3600;i++){
			nm+=x;
			if(nm>=60){
				nh+=nm/60;
				nm%=60;
			}
			if(nh>=24){
				nh%=24;
			}
			
			if(nh/10==nm%10&&nh%10==nm/10){
				ans++;
			}
			if(nh==sh&&nm==sm){
				break;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

E. Binary Deque

题意:

有多组数据。每组数据给出 n 个数,每个数为 0 或 1 。你可以选择从两边删数,求至少删几个数才可以使剩下的数总和为 s 。如果不能达到 s ,则输出 −1 。

思路:很明显的,数组本身的和小于s,肯定无解

我们可以把剩下的记录成这样一个模型:可以采取类似前缀和的方式,然后双指针计算l ~ r之间的和,如果小则r ++大则l++,相等则实时更新答案。

// Code Start Here	
	int t;
	cin >> t;
	while(t--){
		int n , s;
		cin >> n >> s;
		vector<int> a(n);
		int sum = 0;
		for(int i = 0;i<n;i++){
			cin >> a[i];
			sum += a[i];
		}
		int l = 0,r = 0;
		int ans = INF;
		if(sum <s)cout <<"-1\n";
		else{
			sum = a[0];
			while(l < n && r <n){
				if(sum == s){
					ans = min(n + l - r - 1,ans);
					r ++;
					sum += a[r];
				}
				else if(sum > s){
					sum -= a[l];
					l++;
				}
				else{
					r++;
					sum += a[r];
				}
			}
			cout << ans << endl;
		}
	}

F. 3SUM

题意:

给出一个长度为 n 的正整数数组 a,判断是否存在三个不同的下标 i,j,k,使 ai​+aj​+ak​以数字 3 结尾。

思路:看末尾数字相加 = 3即可,很容易联想到遍历一下末尾数字都有哪些,然后组合一下,能形成3则Yes。

更具体的,可以开一个数组来记录出现次数,然后遍历即可

// Code Start Here
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		vector<int>a(n + 1, 0);
		vector<int> cnt(11, 0);
		for (int i = 1; i <= n; ++i) {
			cin >> a[i];
			++cnt[a[i] % 10];
		}
		bool f = false;
		for (int i = 0; i <= 9; ++i) {
			for (int j = i; j <= 9; ++j) {
				for (int k = j; k <= 9; ++k) {
					if ((i + j + k) % 10 - 3) continue;
					--cnt[i], --cnt[j], --cnt[k];
					if (cnt[i] >= 0 && cnt[j] >= 0 && cnt[k] >= 0) {
						f = true;
					}
					++cnt[i], ++cnt[j], ++cnt[k];
				}
			}
		}
		if (f)cout << "Yes\n";
		else cout << "No\n";
	}

G. 2^Sort

题意:

给你一个长度为 n (∑n<2⋅105) 的数组 a,问你在这个数组中,有多少个长度为 k+1 (1≤k<n) 的区间,符合以下的条件:

2^0⋅a_i​  <  2^1⋅a_i+1​  <  2^2⋅a_i+2​  <  ⋯  <  2^k⋅a_i+k​

思路:

观察到原不等式满足这样一个关系:

a_i < a_i+1 *2

所以即求最长一段子区间是否满足题意即可

// Code Start Here
	int t;
	cin >> t;
	while (t--) {
		int n , x;
		cin >> n >>x;
		vector<int> a(n+1);
		vector<int> b(n+1,0);
		for(int i = 1;i<=n;i++)cin >> a[i];
		for(int i = 1;i<n;i++){
			if(a[i] >= a[i+1] * 2){
				b[i] = -1;
			}
		}
		b[n] = -1;
		int now = 0,ans = 0;
		for(int i = 1;i<=n;i++){
			if(b[i] == 0)now++;
			else{
				if(now >= x){
					ans += now - x + 1;
				}
				now = 0;
			}
		}
		cout << ans << endl;
	}

H. Gambling

题意:

Marian 在一个赌场,赌场的游戏规则如下:

每一轮开始前,玩家选一个在 1 到 1e9 。然后,掷出一个有着 1e9 面的骰子,会随机出现一个在 1 与 1e9 之间的数。如果玩家猜对了,他们的钱就会翻一番,否则他们的钱会被折半。

Marian 可以预测未来,他知道在接下来 n 轮里骰子上的数,即 x1​,x2​,...,xn​。

Marian 会选择三个整数 a,l 和 r(l≤r)。他会玩 r−l+1 轮。每一轮,他都猜同一个数 a。一开始(在第 l 轮之前)他有 1 美元。

Marian 请你帮助他决定 a,l 和 r(1≤a≤1e9,1≤l≤r≤n),让他最后的钱最多。

思路:观察到每次猜对数字都会翻倍,显然要在某个区间之内猜对最多,猜错少,然后最大化猜对-猜错的次数。

于是可以建立模型:给定数组 x[] 和 n,求出数组中的一个值 a 和区间 [l,r],使得在区间 [l,r] 中等于 a 的值和不等于 a 的值得个数的差最大。

观察到数组范围很大,需要离散化,于是开一个map<int,vector<int>>记录即可

// Code Start Here
	int t;
	cin >> t;
	while (t--) {
		map<int, vector<int >> mp;
		int n;
		cin >> n;
		vector<int> a(n + 1);
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			mp[a[i]].push_back(i);
		}
		int ans = 1;
		int max_val = a[1], ans_l = 1, ans_r = 1;
		for (auto [num, vec] : mp) {
			int cnt = 1;
			int frt = vec[0],lst = vec[0];
			int now_val = num;
			for (int j = 1; j < sz(vec); j++) {
				cnt -= (vec[j] - lst - 2);
				if (cnt <= 0) cnt = 1, frt = vec[j];
				if (cnt > ans) {
					ans_l = frt;
					ans_r = vec[j];
					ans = cnt;
					max_val = now_val;
				}
				lst = vec[j];
			}
		}
		cout << max_val << " " << ans_l << " " << ans_r << endl;
	}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值