Codeforces Round 815 (Div. 2)

发布时间 2023-12-17 13:39:41作者: 加固文明幻景

基本情况

脑子太不清楚了。

A题有思路,但是各种细节问题(数论题太不熟练了),错了好几次才过。

B题直接分析数据愣猜一个解,猜对了。

A. Burenka Plays with Fractions

Problem - A - Codeforces

难点在分析输出 \(1\) 的情况。

我的想法是通分,然后直接比分子是否互相整除,想法很对,但是实现一直犯病。

  • 本意是为了防止爆long long 所以先对两个分数约分一下,但是这样写代码,第一次 \(a\) 除完 gcd 之后,第二次求得 gcd(a,b) 明显就不是原来的了啊!。

    a /= gcd(a, b); b /= gcd(a, b); c /= gcd(c, d); d /= gcd(c, d);
    

    修改过后

    ll gcd_1 = gcd(a, b), gcd_2 = gcd(c, d);
    a /= gcd_1; b /= gcd_1; c /= gcd_2; d /= gcd_2;
    
  • 通分更是重量级

    a *= lcm(b, d); c *= lcm(b, d)
    

    经典胡言乱语,两个分子光乘分母的最小公倍数是在做什么?肯定要除去对应地分母啊。

    a *= lcm(b, d) / b;  c *= lcm(b, d) / d;
    

终于AC。

void solve()
{
	ll a, b, c, d;
	std::cin >> a >> b >> c >> d;
	if (a * d == b * c) {std::cout << 0 << std::endl; return ;}
	if (a == 0 || c == 0) {std::cout << 1 << std::endl; return ;}
	ll gcd_1 = gcd(a, b), gcd_2 = gcd(c, d);
	a /= gcd_1; b /= gcd_1; c /= gcd_2; d /= gcd_2;
	a *= lcm(b, d) / b;  c *= lcm(b, d) / d;
	if (a % c == 0 || c % a == 0)  {std::cout << 1 << std::endl; return ;}
	std::cout << 2 << std::endl; return ;
}

B. Interesting Sum

Problem - B - Codeforces

猜的解法,不会证明:

void solve()
{
	int n; std::cin >> n;
	std::vector<int> a(n + 10);
	for (int i = 1; i <= n; i++) std::cin >> a[i];
	std::sort(a.begin() + 1, a.begin() + n + 1);
	std::cout << a[n] + a[n - 1] - a[1] - a[2] << std::endl;
}

证明如下:

思考正解,要让原式最大,就要让两个 \(\max\) 得到的值最大,\(\min\) 得到的值最小。

什么最大?什么最小?当然是最大、次大、最小、次小这四个值!

这时有人要问了:你怎么保证一定能把这四个值分成符合条件的两组呢?

干脆枚举,简洁明了。设最大、次大、最小、次小分别是 \(a,b,c,d\)

  • \(abcd\),可以变成 \(a|bc|d\)
  • \(abdc\),可以变成 \(a|bd|c\)
  • \(adbc\),可以变成 \(|ad|bc\)
  • \(\cdots\)

这说明了我们的猜想是正确的(实际上这就是分割一个环)。

就这样得到最优的 \(O(n)\) 做法,输出 \(a+b-c-d\) 即可。