Codeforces Round #558 (Div. 2)

Codeforces Round #558 (Div. 2) 题解

A Eating Soup

分类讨论一下

\(m\) 个断点最多可以将环分成 \(m\) 段,而剩下 \(n-m\) 个点最多可以成为 \(n-m\) 段,取个 \(\min\) 即可

注意 \(m=0\) 时是一个环答案为 \(1\)

// Copyright lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef std::pair<int, int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<long long, long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
#define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)

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

int n, m;

void work() {
  n = read(), m = read();
  if (m == 0) {
    puts("1");
    return;
  }
  int num = n - m;
  printf("%d\n", min(num, m));
}

int main() {
  #ifdef LZT
    freopen("in", "r", stdin);
  #endif

  work();

  #ifdef LZT
    Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
  #endif
}

B Cat Party

倒着枚举长度并且维护每一个出现次数的个数

就是维护出现次数为 \(i\) 的数字有多少个

显然出现次数最多只能有两种(因为你只能修改 \(1\) 个数,也就只能修改一个出现次数)

然后就分类讨论一下最后删掉的是哪个即可

// Copyright lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef std::pair<int, int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<long long, long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
#define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)

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

const int maxn = 100100;
int n, cnt;
int a[maxn];
int b[maxn], num[maxn];

void work() {
  n = read();
  rep(i, 1, n) a[i] = read(), b[a[i]]++;
  cnt = 0; set<int> col;
  rep(i, 1, 100000) {
    if (b[i]) {
      num[b[i]]++;
      cnt++, col.insert(b[i]);
    }
  }
  rrep(i, n, 2) {
    int nw = *col.begin();
    if (num[nw] == 1 && col.size() > 1) nw = *(++col.begin());
    if (col.size() <= 2) {
      bool ok = 0;
      if (col.size() == 1) {
        int nw = *col.begin();
        if (nw == 1 || num[nw] == 1) ok = 1;
        else ok = 0;
      } else {
        int A = *col.begin(), B = *(++col.begin());
        if (num[A] == 1 && A == 1) ok = 1;
        else if (num[B] == 1 && B == 1) ok = 1;
        else if (num[B] == 1 && B == A + 1) ok = 1;
        else ok = 0;
      }
      if (ok) {
        printf("%d\n", i);
        return;
      }
    }
    num[b[a[i]]]--;
    if (num[b[a[i]]] == 0) col.erase(b[a[i]]);
    b[a[i]]--;
    if (b[a[i]]) {
      num[b[a[i]]]++;
      if (num[b[a[i]]] == 1) col.insert(b[a[i]]);
    }
    else cnt--;
  }
  puts("1");
}

int main() {
  #ifdef LZT
    freopen("in", "r", stdin);
  #endif

  work();

  #ifdef LZT
    Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
  #endif
}

C Power Transmission

答案显然是 \(calc(\text{不同的直线数量}) - \sum_{\text{斜率k}} calc(\text{斜率为k的直线数量})\)

其中 \(calc(x)=x*(x-1)/2\)

然后就枚举每两个点形成一条线,然后计数即可

// Copyright lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef std::pair<int, int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<long long, long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
#define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)

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

const int maxn = 1010;
int n;
pii p[maxn];

bool sm(double x, double y) {
  return fabs(x - y) <= 1e-8;
}

struct Line {
  // Ax + By + C = 0
  double A, B, C;
  bool operator == (const Line &b) const {
    return sm(A, b.A) && sm(B, b.B) && sm(C, b.C);
  }
  bool operator < (const Line &b) const {
    if (sm(A, b.A)) {
      if (sm(B, b.B)) return C < b.C;
      return B < b.B;
    }
    return A < b.A;
  }
  void init() {
    if (A == 0) C = C / B, B = 1;
    else B = B / A, C = C / A, A = 1;
  }
  double calc() {
    init();
    if (A == 1) return B;
    else return 1e30;
  }
};

map<double, map<double, int> > M;
map<double, int> shit;
vector<Line> v;

void work() {
  n = read();
  rep(i, 1, n) p[i].fi = read(), p[i].se = read();
  ll num = 0;
  rep(i, 1, n) rep(j, i + 1, n) {
    Line nw;
    nw.A = p[j].se - p[i].se;
    nw.B = p[i].fi - p[j].fi;
    nw.C = 0 - p[i].fi * nw.A - p[i].se * nw.B;
    nw.init();
    double k = nw.calc();
    if (M[k][nw.C] == 0) {
      M[k][nw.C] = 1;
      num++; shit[k]++;
    }
  }
  num = num * (num - 1) / 2;
  for (map<double, int>::iterator it = shit.begin(); it != shit.end(); it++) {
    int nw = it -> se;
    num = num - nw * 1ll * (nw - 1) / 2;
  }
  printf("%lld\n", num);
}

int main() {
  #ifdef LZT
    freopen("in", "r", stdin);
  #endif

  work();

  #ifdef LZT
    Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
  #endif
}

D Mysterious Code

首先预处理 \(S[i][j]\)\(T[i][j]\) 分别表示当前串的后缀与 \(s/t\) 的前缀的最长公共子串长度为 \(i\) (也就是只有最后 \(i\) 位有用,前面的都忽略),然后下一个位置填了字母 \(j\) 之后那个最长公共子串的长度(类似 \(kmp\)\(fail\)

直接 \(dp\) \(f[i][j][k]\) 表示当前长度为 \(i\),在第一个串上的位置是 \(j\) ,在第二个串上的位置是 \(k\) 的最大 \(f(c',s)-f(c',t)\)

然后转移就暴力枚举一下下一个是啥

// Copyright lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef std::pair<int, int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<long long, long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
#define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)

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

const int maxn = 1010;
int n, m, len;
char s[maxn], t[maxn], c[maxn];
int f[maxn][55][55];
int S[55][26], T[55][26];

inline void getmx(int &x, int y) {
  if (x < y) x = y;
}

void work() {
  scanf("%s", c + 1); len = strlen(c + 1);
  scanf("%s", s + 1); n = strlen(s + 1);
  rep(i, 0, n) rep(j, 0, 25) {
    int len = i + 1;
    rrep(k, min(len, n), 1) {
      bool flag = true;
      rep(_, 1, k - 1) if (s[i - k + _ + 1] != s[_]) {
        flag = false; break;
      }
      if (s[k] - 'a' != j) flag = false;
      if (flag) {
        S[i][j] = k;
        break;
      }
    }
    // cout<<i<<' '<<j<<' '<<S[i][j]<<endl;
  }
  scanf("%s", t + 1); m = strlen(t + 1);
  rep(i, 0, m) rep(j, 0, 25) {
    int len = i + 1;
    rrep(k, min(len, m), 1) {
      bool flag = true;
      rep(_, 1, k - 1) if (t[i - k + _ + 1] != t[_]) {
        flag = false; break;
      }
      if (t[k] - 'a' != j) flag = false;
      if (flag) {
        T[i][j] = k;
        break;
      }
    }
    // cout<<i<<' '<<j<<' '<<T[i][j]<<endl;
  }
  rep(i, 0, len) rep(j, 0, n) rep(k, 0, m) f[i][j][k] = -1e9;
  f[0][0][0] = 0;
  rep(i, 0, len - 1) rep(j, 0, n) rep(k, 0, m) {
    if (f[i][j][k] == -1e9) continue;
    if (c[i + 1] != '*') {
      int nw = c[i + 1] - 'a', pl = 0;
      if (S[j][nw] == n) pl++;
      if (T[k][nw] == m) pl--;
      getmx(f[i + 1][S[j][nw]][T[k][nw]], f[i][j][k] + pl);
    } else {
      rep(nw, 0, 25) {
        int pl = 0;
        if (S[j][nw] == n) pl++;
        if (T[k][nw] == m) pl--;
        getmx(f[i + 1][S[j][nw]][T[k][nw]], f[i][j][k] + pl);
      }
    }
  }
  int ans = -1e9;
  rep(j, 0, n) rep(k, 0, m) {
    getmx(ans, f[len][j][k]);
  }
  printf("%d\n", ans);
}

int main() {
  #ifdef LZT
    freopen("in", "r", stdin);
  #endif

  work();

  #ifdef LZT
    Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
  #endif
}

E Magical Permutation

// Copyright lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef std::pair<int, int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef std::pair<long long, long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i, j, k)  for (register int i = (int)(j); i <= (int)(k); i++)
#define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)

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

const int maxn = 200200;
int n, ans, pos;
int a[maxn], lb[20];
vector<int> vec;
bool vis[maxn << 2];

void add(int v) {
  int tmp = v;
  rrep(i, 20, 0) {
    if (v & (1 << i)) {
      if (lb[i]) v ^= lb[i];
      else {
        vec.pb(tmp);
        lb[i] = v;
        break;
      }
    }
  }
}

void dfs(int v, int num) {
  printf("%d ", v); vis[v] = 1;
  if (num == (1 << ans)) return;
  rep(i, 0, vec.size() - 1) if (!vis[v ^ vec[i]]) {
    dfs(v ^ vec[i], num + 1);
    break;
  }
}

void work() {
  n = read();
  rep(i, 1, n) a[i] = read();
  sort(a + 1, a + n + 1);
  ans = 0, pos = 1;
  rep(i, 1, 20) {
    while (pos <= n && a[pos] < (1 << i)) {
      add(a[pos]);
      pos++;
    }
    bool flag = true;
    rep(j, 0, i - 1) if (!lb[j]) flag = false;
    if (flag) ans = i;
  }
  memset(lb, 0, sizeof(lb));
  vec.clear();
  rep(i, 1, n) {
    if (a[i] < (1 << ans)) add(a[i]);
  }
  printf("%d\n", ans);
  dfs(0, 1);
}

int main() {
  #ifdef LZT
    freopen("in", "r", stdin);
  #endif

  work();

  #ifdef LZT
    Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
  #endif
}

posted @ 2019-05-10 09:36  wawawa8  阅读(658)  评论(0编辑  收藏  举报