AtCoder Regular Contest 112 题解

本文解析了两道算法题目,包括寻找符合条件的整数对数目及通过有限操作获取数值范围的方法。

A. A - B = C

A题题目链接
【题解】题意要求符合题意的对数。我们考虑对于每一个C而言,有如下的对数:(L, L + C), … ,(R - C, R), 即总共R - L + 1 - C对。而L <= C <= R 且 C <= R - L(如果C > R - L则没有符合题意的对数),则 L <= C <= R - L,但是显然L, R - L谁大谁小是不清楚的,需要讨论情况。如果L > R - L,则没有符合题意的对数,输出为0;否则即存在若干个C, 对于每一个C,(R - L + 1 - maxC) + … + (R - L + 1 - minC)即是一个等差数列求和,用公式即可。

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

typedef long long ll;
int t;

ll sum(ll a, ll b) {
	return (a + b) * (b - a + 1) / 2;
}

int main() {
	ios::sync_with_stdio(false);
	cin >> t;
	while(t --) {
		ll l, r;
		cin >> l >> r;
		ll minC = l, maxC = r - l;
		if(minC > maxC) cout << "0\n";
		else {
			cout << sum(r - l + 1 - maxC, r - l + 1 - minC) << endl;
		}
	}
	return 0;
} 

B. B—B

B题题面链接
【题解】根据题意,Snuke初始有一个数B, 然后他通过支付一定的钱来使这个数变为另外一个数,可以使用无数次的以下两个操作,1)支付一元让这个数乘-1,2)支付两元使这个数减1,问Snuke在最多C元的情况下可以得到多少个数?

先考虑恰好花费C的时候,能得到的取值方案数。花费为1的操作对拓宽方案数并无多大意义,应重点注意花费为2减1的操作。C的奇偶性不定,需要讨论。

  1. C为奇数,那么C最多可以使用n = C / 2次-1操作。求方案数,讨论的是极值范围(这一点A题也是,只不过B题在此基础加上了奇偶性的讨论)。求极值的话,首先极值就是尽量-1,再通过乘-1操作使它成最大值/最小值;然后由于-1操作也是连续的,所以只需把某些操作替换成两次没有意义的乘-1操作就好了。最大值:先-n再乘-1,得n - B;最小值:先乘-1再-n,得-B- n,[-B - n, n - B],即[-B - C / 2, C / 2 - B]。【(-B - n) - (n - B) = -2n < 0)】
  2. C为偶数,那么C恰好最多可以使用n = C / 2次-1操作,要么不使用乘-1操作,要么使用两次乘-1操作。对于前一种操作,得到极值B - n;对于后一种操作,要么B - (n - 1) * (-1)^2 = B - (n - 1),要么 (B*(-1) - (n - 1))*(-1) = B + (n - 1)。则最小值是B - n, 最大值是B + (n - 1),即[B - n, B + (n - 1)],[B - C / 2, B + C / 2 - 1]。
    最后考虑至多花费C的时候,能得到的取值方案数。这么多方案很难一个个去容斥,思考一下:花费C = k + 2能取到的方案数完全包含C = k 的方案数,因而我们只需考虑C, C -1的方案数交集就好了,因为C, C - 1时包含了前面的所有方案数,容斥这两种情况下的就好了。设两个恰好花费的区间分别为(a, b),(c, d)容斥一下就好了。但是注意如果C = 1的话就没有C和C - 1的情况了。如果C = 1: 如果B = 0, 则输出0, 否则输出2。
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

void solve(ll B, ll C, ll& a, ll& b) {
	if(C & 1) {
		a = -B - C / 2;
		b = C / 2 - B;
	} else {
		a = B - C / 2;
		b = B + (C / 2 - 1);
	}
}

int main() {
	ios::sync_with_stdio(false);
	ll B, C;
	cin >> B >> C;
	if(C == 1) {
		if(B == 0) cout << "1\n";
		else cout << "2\n";
		return 0;
	}	
	ll a, b, c, d;
	solve(B, C, a, b);
	solve(B, C - 1, c, d);
	cout << max(0ll, b - a + 1) + max(0ll, d - c + 1) - max(0ll, min(b, d) - max(a, c) + 1) << endl; 
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值