Codeforces Round #653 (Div. 3)(A, B, C, D, E1详解)

Codeforces Round #653 (Div. 3)

Required Remainder

Thinking(binary search)

既然是找最大值问题,我又懒得去推式子,于是我直接就上了一个二分,二分写法比结论稍微繁琐了一点吧,但是还是挺好想的。

根据题意,我们的任务就是找到一个最大的数,满足 a n s = k ∗ x + y < = n ans = k * x + y <= n ans=kx+y<=n,于是我们就可以通过二分枚举 k k k,来得到我们的答案。通过题目给定的 x , y , z x, y, z x,y,z的范围,我们可以确定二分的区间最多不过 0   1 9 0 ~ 1^9 0 19

Coding

#include 
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-7;

inline ll read() {
  ll f = 1, x = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    if(c == '-')  f = -1;
    c = getchar();
  }
  while(c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (48 ^ c);
    c = getchar();
  }
  return f * x;
}

const int N = 1e6 + 10;

char str[N];

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int _ = read();
  while(_--) {
      ll x = read(), y = read(), n = read();
      ll l = 0, r = 1e9 + 10;
      while(l < r) {
        ll mid = l + r + 1 >> 1;
        if(mid * x + y <= n)  l = mid;
        else r = mid - 1;
      }
      printf("%lld\n", l * x + y);
  }
  return 0;
}

Multiply by 2, divide by 6

Thinking

判断能否通过0个或者多个乘二的操作,使数字变成6的倍数。我们想想6的两个质因子 2 , 3 2, 3 2,3,要想达到这个目的,对于初始的 n n n,只可能有这两种质因子,否则我们一定达不到我们的目标。于是我们可以先对 n n n,进行 2 , 3 2, 3 2,3的质因数提取,假设得到的 2 2 2的因子个数是 n u m 2 num2 num2 3 3 3的因子个数是 n u m 3 num3 num3,因为我们是同时消去 2 , 3 2, 3 2,3因子的,并且只能增加或者不增加 2 2 2的因子个数,所以只有当 n u m 2 < = n u m 3 num2 <= num3 num2<=num3时,才能保证我们可以消去所有的 2 , 3 2, 3 2,3因子,最后变成 1 1 1

Coding

#include 
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-7;

inline ll read() {
  ll f = 1, x = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    if(c == '-')  f = -1;
    c = getchar();
  }
  while(c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (48 ^ c);
    c = getchar();
  }
  return f * x;
}

const int N = 1e6 + 10;

char str[N];

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int _ = read();
  while(_--) {
    ll n = read();
    int num2 = 0, num3 = 0;
    while(n % 3 == 0) {
      n /= 3;
      num3++;
    }
    while(n % 2 == 0) {
      n /= 2;
      num2++;
    }
    //最后n不是1说明还存在其他的质因子。
    if(n != 1 || num2 > num3) puts("-1");
    else  printf("%d\n", num3 + num3 - num2);
  }
  return 0;
}

Move Brackets

Thinking(Stack)

我们先找到所有的符合匹配的括号,最后就只剩下一种非法的括号了,以这种形式存在 ) ( ) ( )(形成 ) ) ) ) ) ( ( ( ( ( )))))((((( )))))(((((这样的排列,所以我们只需要将其后面的移到前面去,或者前面的移到后面去,任选一种进行操作,因此我们的花费将会是最后无法匹配的括号的对数,也就是栈中的元素的一半。

Coding

#include 
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-7;

inline ll read() {
  ll f = 1, x = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    if(c == '-')  f = -1;
    c = getchar();
  }
  while(c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (48 ^ c);
    c = getchar();
  }
  return f * x;
}

const int N = 1e6 + 10;

char str[N];

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int _; cin >> _;
  while(_--) {
    int n; cin >> n;
    stack<char> stk;
    for(int i = 1; i <= n; i++) {
      char temp;  cin >> temp;
      if(stk.empty() || stk.top() == temp || temp == '(')  stk.push(temp);
      else  stk.pop();
    }
    printf("%d\n", stk.size() / 2);
  }
  return 0;
}

Zero Remainder Array

Thinking

对于给定的序列,我们需要的就是 x ( m o d k ) = ( 1 , 2 … … k − 2 , k − 1 ) x \pmod k = (1, 2 …… k - 2, k - 1) x(modk)=(1,2k2,k1),这样的数,才能使我们的序列变成都是 k k k的倍数,假定 k = 4 k = 4 k=4,数组中存在两个数分别为 3 , 7 3, 7 3,7, 他们有一个共同点 3 ( m o d k )   = 7 ( m o d k ) 3 \pmod k \ = 7 \pmod k 3(modk) =7(modk),也就是说我们在 x ( m o d k ) x \pmod k x(modk) 0 − > k − 1 0 -> k - 1 0>k1,的一趟循环中,最多只能使其中的一个数变成 a i ( m o d k ) = 0 a_i \pmod k = 0 ai(modk)=0,想必看到这里应该就搞懂了这道题了,我们就是要找到 a i ( m o d k ) a_i \pmod k ai(modk)后出现的次数最多的非零数,当有多个出现次数相同的数时我们取 a i ( m o d k ) a_i \pmod k ai(modk)的最小值,因为那个最小值一定是当 x x x足够大的时候才会满足条件。

Coding

#include 
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-7;

inline ll read() {
  ll f = 1, x = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    if(c == '-')  f = -1;
    c = getchar();
  }
  while(c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (48 ^ c);
    c = getchar();
  }
  return f * x;
}

const int N = 2e5 + 10;

int a[N];

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int _ = read();
  while(_--) {
    int n = read(), k = read();
    for(int i = 1; i <= n; i++) {
      a[i] = read();
      a[i] %= k;
    }
    sort(a + 1, a + 1 + n, greater<int> ());
    int now_num = 1, ansn = a[1], num = 1;
    for(int i = 2; i <= n && a[i] != 0; i++) {
      if(a[i] == a[i - 1])  now_num++;
      else  now_num = 1;
      if(now_num >= num)  ansn = a[i], num = now_num;
    }
    if(ansn == 0){
      puts("0");
      continue;
    }
    // cout << num << " " << ansn << endl;
    printf("%lld\n", 1ll * k * (num - 1) + k - ansn + 1);
  }
  return 0;
}

Reading Books (easy version)

Thinking(Sort, greedy)

题意这里就不说明了,对于给定的条件,我们要同时满足 A l i c e a n d B o b Alice and Bob AliceandBob都要读至少 k k k本书,所以我们可以指定一个策略,不管这本书是 A l i c e o r B o b Alice or Bob AliceorBob喜欢,还是他们两同时喜欢,我们都同时增加 A l i c e a n d B o b Alice and Bob AliceandBob的当前的书的数量,因此在之前我们就需要对书本分类 A l i c e Alice Alice喜欢的数组a, B o b Bob Bob喜欢的数组b,两个人都喜欢的数组c。接下来就时对这三个数组分别按照元素大小从小到大进行排序

当我们当前枚举的 a i + b j < = c k a_i + b_j <= c_k ai+bj<=ck时我们显然贪心的选择 a i , b j a_i, b_j ai,bj这两本书,所以我们的总花费将会变成 a n s + = a i + b j ans += a_i + b_j ans+=ai+bj,否则的话我们将会选择 c k c_k ck,花费将变成 a n s + = c k ans += c_k ans+=ck

当我们第一个点枚举完了后,大致存在三种情况 a a a不可选, b b b不可选, c c c不可选。

所以接下来的枚举我们必须分类讨论了当 a ∣ ∣ b a || b ab,不可选的时候,我们要达到条件只能通过选择 c c c来进行。否则的话我们就只能选择 a , b a, b a,b两个组合选取了。

Code

#include 
#define mp make_pair
// #define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-7;

inline ll read() {
  ll f = 1, x = 0;
  char c = getchar();
  while(c < '0' || c > '9') {
    if(c == '-')  f = -1;
    c = getchar();
  }
  while(c >= '0' && c <= '9') {
    x = (x << 1) + (x << 3) + (48 ^ c);
    c = getchar();
  }
  return f * x;
}

const int N = 2e5 + 10;

struct Node {
  int value, fa, fb;
  void input() {
    value = read(), fa = read(), fb = read();
  }
  void out() {
    printf("%d %d %d\n", value, fa, fb);
  }
  bool operator < (const Node & t) const {
    return value < t.value;
  }
}a[N], b[N], c[N], in;
//结构体就是数组的用处,不用管。是我自己一开始思路想的有点复杂,然后就写了这么一个结构体。

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int n = read(), k = read(), na = 0, nb = 0, nc = 0;
  for(int i = 1; i <= n; i++) {
    in.input();
    if(in.fa && in.fb)  c[++nc] = in;
    else if(in.fa)  a[++na] = in;
    else if(in.fb)  b[++nb] = in;
    //一定要注意特判 0 0的情况。
  }
  // cout << na << " " << nb << " " << nc << endl;
  sort(a + 1, a + 1 + na);
  sort(b + 1, b + 1 + nb);
  sort(c + 1, c + 1 + nc);
  int pa = 1, pb = 1, pc = 1, flag = 0;
  int numa = 0, numb = 0;
  ll ans = 0;
  while(pa <= na && pb <= nb && pc <= nc) {
    if(a[pa].value + b[pb].value <= c[pc].value) {
      ans += a[pa].value + b[pb].value;
      pa++, pb++;
    }
    else {
      ans += c[pc].value;
      pc++;
    }
    numa++, numb++;
    if(numa >= k && numb >= k) {
      flag = 1;
      break;
    }
  }
  // cout << ans << " " << numa << " " << numb << endl;
  if(flag) {
    printf("%lld\n", ans);
    return 0;
  }
  if(pa > na || pb > nb) {
    while(pc <= nc) {
      ans += c[pc].value;
      pc++;
      numa++, numb++;
      if(numa >= k && numb >= k) {
        flag = 1;
        break;
      }
    }
  }
  else {
    while(pa <= na && pb <= nb) {
      ans += a[pa].value + b[pb].value;
      pa++, pb++;
      numa++, numb++;
      if(numa >= k && numb >= k) {
        flag = 1;
        break;
      }
    }
  }
  if(flag) {
    printf("%lld\n", ans);
    return 0;
  }
  puts("-1");
  return 0;
}

你可能感兴趣的:(Codeforces)