CF1857 Div.3 A~F 题解

文章较长,点个赞支持作者吧!!!

CF1857A

luogu题目链接
codeforces题目链接

分析

由于 奇数 + 奇数 = 偶数 , 偶数 + 偶数 = 偶数 奇数+奇数=偶数,偶数+偶数=偶数 奇数+奇数=偶数,偶数+偶数=偶数,所以我们只需判断 a a a 数组的总和是否为偶数即可。

代码

代码过于简单不放了……

CF1857B

luogu题目链接
codeforces题目链接

分析

既然要求值最大,那么越高位肯定越要进位,如果当前位要进位必须是当前位 ≥ 5 \ge 5 5,或者是当前位及后面连续一段都是 4 4 4,且段的末尾的后一个位 ≥ 5 \ge 5 5,模拟即可。

代码

有点长,放出来占篇幅……

CF1857C

luogu题目链接
codeforces题目链接

分析

考虑将数组 b b b 升序排序,因为最小值跟其他数取 min ⁡ \min min 必然是最小值,所以 b 1 b_1 b1 一定是最小值,在把最小值去掉,重复以上操作即可,最大值是任何数都行,最好取到 1 0 9 10^9 109

m = n × ( n − 1 ) 2 m=\frac{n\times (n-1)}{2} m=2n×(n1) 由于最小值出现了 n − 1 n-1 n1 次,次小值出现了 n − 2 n-2 n2 次,所以可以按照代码里那样输出答案,具体看代码。

代码

# include <bits/stdc++.h> 

using namespace std;
using PII = pair <int, int>;

const int N = 5e5 + 5;
int T, n, b[N];

signed main () {
  for (cin >> T; T; T --) {
    cin >> n;
    int len = n;
    n = n * (n - 1) / 2;
    for (int i = 1; i <= n; i ++) {
      cin >> b[i];
    }
    sort (b + 1, b + n + 1);
    for (int i = 1, j = 1; i <= n; i += len - j, j ++) {
      cout << b[i] << " ";
    }
    cout << "1000000000\n";
  }
  return 0;
}

CF1857D

luogu题目链接
codeforces题目链接

分析

一个很常见的套路:先将相同的放在一起,先对式子移项: a u − a v ≥ b u − b v → a u − b u ≥ a v − b v a_u-a_v\ge b_u-b_v\to a_u-b_u\ge a_v-b_v auavbubvaubuavbv,发现只有 a i − b i a_i-b_i aibi 最大的 i i i 才能向所有点连边所以统计最大值,输出即可。

代码

# include <bits/stdc++.h> 
# define int long long

using namespace std;
using PII = pair <int, int>;
const int N = 1e5 + 5, inf = 0x3f3f3f3f;
const long long linf = 0x3f3f3f3f3f3f3f3f;

int T, n, a[N], b[N];

signed main () {
  for (cin >> T; T; T --) {
    scanf ("%lld", &n);
     for (int i = 1; i <= n; i ++) {
      scanf ("%lld", &a[i]);
    } 
    for (int i = 1; i <= n; i ++) {
      scanf ("%lld", &b[i]);
    } 
    int maxn = -linf, cnt = 0;
    for (int i = 1; i <= n; i ++) {
      maxn = max (maxn, a[i] - b[i]);
    }
    for (int i = 1; i <= n; i ++) {
      if (a[i] - b[i] == maxn) {
        cnt ++;
      }
    } 
    printf ("%lld\n", cnt);
    for (int i = 1; i <= n; i ++) {
      if (a[i] - b[i] == maxn) {
        printf ("%lld ", i);
      }
    } 
    printf ("\n");
  }
  return 0;
}

CF1857E

luogu题目链接
codeforces题目链接

分析

发现点被覆盖的次数的和其实就是每个 p i p_i pi 连出的线段的长度和。

先对 p p p 数组升序排序,发现如果从点 p i p_i pi 换到点 p i + 1 p_{i+1} pi+1,就是 p i + 1 p_{i+1} pi+1 左边的所有点都增加了 p i + 1 p_{i+1} pi+1 p i p_i pi 这一段,所有 p i + 1 p_{i+1} pi+1 右边的(包括 p i + 1 p_{i+1} pi+1)都减少了 p i + 1 p_{i+1} pi+1 p i p_i pi 这一段,统计前缀和和后缀和计算即可。

代码

# include <bits/stdc++.h> 
# define int long long
# define x first
# define y second

using namespace std;
using PII = pair <int, int>;
const int N = 5e5 + 5, inf = 0x3f3f3f3f;
const long long linf = 0x3f3f3f3f3f3f3f3f;

PII a[N];
int T, n, ans[N], fsum[N], bsum[N];

signed main () {
  for (cin >> T; T; T --) {
    scanf ("%lld", &n);
    for (int i = 1; i <= n; a[i].y = i, i ++) {
      cin >> a[i].x;
    }
    sort (a + 1, a + n + 1);
    fill (bsum + 1, bsum + n + 2, 0);
    for (int i = 1, j = n; i <= n; i ++, j --) {
      fsum[i] = fsum[i - 1] + a[i].x;
      bsum[j] = bsum[j + 1] + a[j].x;
    }
    for (int i = 1; i <= n; i ++) {
      int t = a[i].x * (i - 1) - fsum[i - 1] - 1 + bsum[i + 1] - a[i].x * (n - i) + n + 1;
      ans[a[i].y] = t;
    }
    for (int i = 1; i <= n; i ++) {
      cout << ans[i] << " ";
    }
    cout << '\n';
  }
  return 0;
}

CF1857F

luogu题目链接
codeforces题目链接

分析

首先可以由第一个条件知道 x − a i = a j x-a_i=a_j xai=aj,那么第二个条件就变成了 a i ( x − a i ) = y a_i(x-a_i)=y ai(xai)=y,把括号 OK 掉即为 − a i 2 + a i x = y -{a_i}^2+a_ix=y ai2+aix=y,也就是 − a i 2 + x a i − y = 0 -{a_i}^2+xa_i-y=0 ai2+xaiy=0,发现是一个一元二次方程,写出公式:

a n s : x ± x 2 − 4 y 2 ans:\frac{x\pm \sqrt{x^2-4y}}{2} ans:2x±x24y

计算即可,用 map 统计每个数出现的次数,假设求出来的两个答案为 a , b a,b a,b,则 m p a × m p b mp_a \times mp_b mpa×mpb 即为答案,若求出来的答案相等则 m p a × ( m p a − 1 ) / 2 mp_a \times (mp_a-1)/2 mpa×(mpa1)/2 为答案。

注意特判如果 Δ = x 2 − 4 y \Delta=x^2-4y Δ=x24y 0 0 0 则此时无解,或求出来的答案不满足条件也无解,此时答案都为 0 0 0

代码

# include <bits/stdc++.h> 
# define int long long

using namespace std;
// using ll = long long;
using PII = pair <int, int>;

const int N = 2e5 + 5;
int T, n, q, x, y, a[N];
map <int, int> mp;

int getans () {
  int d = x * x - 4 * y;
  int a = (x - sqrt (d)) / 2, b = (x + sqrt (d)) / 2;
  if (d < 0 || a + b != x || a * b != y) {
    return 0;
  } if (a == b) {
    return mp[a] * (mp[a] - 1) / 2;
  }
  return mp[a] * mp[b];
}

signed main () {
  for (cin >> T; T; T --) {
    mp.clear();
    cin >> n;
    for (int i = 1; i <= n; i ++) {
      cin >> a[i];
      mp[a[i]] ++;
    }
    for (cin >> q; q; q --) {
      cin >> x >> y;
      cout << getans () << ' ';
    }
    cout << '\n';
  }
  return 0;
}

欢迎阅读QAQ,顺便膜拜各位大佬。

如有 OIer 欢迎跟本蒟蒻交流,或踩爆本蒟蒻。

本蒟蒻 Luogu ID:778022,Luogu name:yhylivedream

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值