其他分享
首页 > 其他分享> > CSP-S 2020

CSP-S 2020

作者:互联网

A. 儒略日

根据题意直接模拟。我的方法是依次以400, 100, 4, 1为周期计算年份然后再算月日。

#include <bits/stdc++.h>
template <class T>
inline void readInt(T &w) {
  char c, p = 0;
  while (!isdigit(c = getchar())) p = c == '-';
  for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
  if (p) w = -w;
}
template <class T, class... U>
inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }

typedef long long LL;
typedef std::pair<int, int> PII;

constexpr int p4 = 365 * 4 + 1, p100 = 365 * 100 + 25 - 1, p400 = 365 * 400 + 100 - 3;
constexpr int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int main() {
  int t; readInt(t);
  while (t--) {
    LL r; readInt(r);
    int year = -4712;
    auto checkYear = [&]() {
      if (year <= 1582) return year % 4 == 0;
      return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
    };
    auto print = [&]() {
      assert(0 <= r && r <= 365);
      if (checkYear() && r >= 31 + 28) {
        if (r == 31 + 28) {
          printf("29 2 ");
          if (year <= 0)
            printf("%d BC\n", -year + 1);
          else 
            printf("%d\n", year);
          return;
        }
        r--;
      }
      int m = 0;
      while (r >= days[m]) r -= days[m++];
      m++, r++;
      if (year <= 0)
        printf("%lld %d %d BC\n", r, m, -year + 1);
      else
        printf("%lld %d %d\n", r, m, year);
    };
    auto extend = [&](int pt) {
      while (year < pt) {
        int span = checkYear() ? 366 : 365;
        if (r < span) break;
        r -= span, year++;
      }
    };
    int pt = year + r / p4 * 4;
    if (pt <= 1582) {
      r %= p4, year = pt;
    } else {
      year = 1580, r -= (1580 + 4712) / 4 * p4;
    }
    extend(1582);
    if (year == 1582) {
      if (r >= 277) r += 10;
      extend(1600);
    }
    if (year == 1600) {
      year += r / p400 * 400, r %= p400;
      if (r >= p100 + 1) {
        r--;
        year += r / p100 * 100, r %= p100;
      }
      if (!checkYear() && r >= p4 - 1) r++;
        year += r / p4 * 4, r %= p4;
      extend(1e9);
    }  
    print();
  }
  return 0;
}

B. 动物园

处理出已有哪些饲料,这些饲料可以养二进制哪些位为1的动物,答案是可以养的数量减去已有的数量。
注意 \(k=64, n = 0\) 时会爆 uint64,这里直接用 long double
实际上,因为所有的 \(q_i\) 互不相同,所以饲料的需求信息其实没啥用,只要统计哪些位在要求中出现即可。

#include <bits/stdc++.h>

template <class T>
inline void readInt(T &w) {
  char c, p = 0;
  while (!isdigit(c = getchar())) p = c == '-';
  for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
  if (p) w = -w;
}
template <class T, class... U>
inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }

constexpr int N(1e6 + 5);
int n, m, c, k;
using ULL = unsigned long long;
int main() {
  readInt(n, m, c, k);
  ULL s = 0, ok = 0;
  for (int i = 1; i <= n; i++) {
    ULL x;
    readInt(x);
    s |= x;
  }
  for (int i = 1, x, y; i <= m; i++) {
    readInt(x, y);
    if (s >> x & 1 ^ 1) ok |= 1ULL << x;
  }
  long double ans = 1;
  for (int i = 0; i < k; i++)
    if (ok >> i & 1 ^ 1) ans *= 2;
  printf("%.0Lf", ans - n);
  return 0;
}

C. 函数调用

题意:有长度为 \(n\) 的序列 \({a_n}\) 和 \(m\) 个函数。函数只有三种:单点加一个数,序列整体乘一个数,依次调用若干函数(不会出现递归)。求依次调用一些函数后的序列 \(a_n\)。

考虑每个加操作被之后的乘操作影响了多少,即,求 \(delta_i\times num_i\) 的系数 \(num_i\)

数据范围中的树提示我们建图。

如果函数 \(f\) 调用了函数 \(g\),那么连有向边 \(f\rightarrow g\)。因为没有递归,所以是DAG,下面在这个DAG上求解。

设 \(multi_i\) 表示调用函数 \(i\) 执行的所有乘法系数之积。

若函数 \(f\) 依次调用了函数 \(g_0, g_1, g_2,\dots g_k\),那么 \(g_i\) 内部的某个加法操作所受的影响可以分为三个部分:

  1. 内部乘法的影响
  2. \(\prod_{j = i + 1}^k multi_j\)
  3. 调用\(f\)的函数 \(F\) 的影响。

将第3条 \(F\) 对其子函数的 影响 也记为 \(num_F\)。

如果 \(F\) 只是一个加法操作,那么这个 \(num\) 就是加法的系数。

转移时,调用 \(f\) 的函数有 \(F_0, F_1, \dots, F_K\),则 \(num_f=\sum \left(num_{F_i}\times\prod multi_j\right)\)。

#include <bits/stdc++.h>
#ifdef LOCAL
#define dbg(args...) std::cerr << "\033[32;1m" << #args << " -> ", err(args)
#else
#define dbg(...)
#endif
inline void err() { std::cerr << "\033[0m\n"; }
template<class T, class... U>
inline void err(const T &x, const U &... a) { std::cerr << x << ' '; err(a...); }
template <class T>
inline void readInt(T &w) {
  char c, p = 0;
  while (!isdigit(c = getchar())) p = c == '-';
  for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
  if (p) w = -w;
}
template <class T, class... U>
inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }

typedef long long LL;
typedef std::pair<int, int> PII;

constexpr int N(1e5 + 5), P(998244353);
inline void inc(int &x, int y) {
  x += y;
  if (x >= P) x -= P;
}
int n, m, a[N], p[N], v[N], d[N];
std::vector<int> g[N];
int multi[N], now[N];
bool vis[N];
void dfs(int x) {
  if (vis[x]) return;
  vis[x] = 1;
  multi[x] = !p[x] && v[x] >= 0 ? v[x] : 1;
  for (int y: g[x]) {
    dfs(y);
    d[y]++;
    multi[x] = 1LL * multi[x] * multi[y] % P;
  }
}
int main() {
  readInt(n);
  for (int i = 1; i <= n; i++) readInt(a[i]);
  readInt(m);
  for (int i = 1; i <= m; i++) {
    int opt; readInt(opt);
    if (opt == 1)
      readInt(p[i], v[i]);
    else if (opt == 2)
      readInt(v[i]);
    else {
      readInt(v[i]);
      while (v[i]--) {
        int x; readInt(x);
        g[i].push_back(x);
      }
      std::reverse(g[i].begin(), g[i].end());
    }
  }
  readInt(v[++m]);
  while (v[m]--) {
    int x; readInt(x);
    g[m].push_back(x);
  }
  std::reverse(g[m].begin(), g[m].end());
  dfs(m);
  for (int i = 1; i <= n; i++)
    a[i] = 1LL * a[i] * multi[m] % P;
  std::queue<int> q;
  q.push(m);
  now[m] = 1;
  while (!q.empty()) {
    int x = q.front(); q.pop();
    if (p[x]) a[p[x]] = (a[p[x]] + 1LL * now[x] * v[x]) % P;
    for (int y: g[x]) {
      inc(now[y], now[x]);
      now[x] = 1LL * now[x] * multi[y] % P;
      if (--d[y] == 0) q.push(y);
    }
  }
  for (int i = 1; i <= n; i++)
    printf("%d%c", a[i], " \n"[i == n]);
  return 0;
}

D. 贪吃蛇

题意:给定长度为 \(n\) 的序列 \(a_n\) 表示 \(n\) 条蛇的长度,蛇 \(i\) 强于 \(j\) 当且仅当 \((a_i, i)>(a_j, j)\)。然后从第一轮开始,每轮最强的蛇可以吃掉最菜的蛇并开启下一轮。当某一轮选择不吃则不会开启下一轮。\(i\) 吃 \(j\) 会使 \(a_i = a_i - a_j\)。每条蛇想在不被吃的情况下吃尽可能多的蛇,问每条蛇都采取最优策略时最后会剩多少条蛇。

最优策略一直都挺劝退的。

如果不会选择不吃,那么会进行 \(n-1\) 轮,最后剩下一条。显然最优策略是这 $n-1 $轮的某个前缀。

第 \(i\) 轮的决策取决于后面的情况而与已经进行的轮无关,

设 \(f(i)\) 表示进行完前 \(i\) 轮(前面的蛇都选择吃)的情况下,总共最多会进行 \(f(i)\) 轮(在第 \(f(i)+1\) 轮选择了不吃)。

设第 \(i\) 轮的最强蛇会在第 \(t_i\) 轮被吃掉,那么 \(f(i)<t_i\) 就表示可以吃,否则不可以吃。

那么 \(f(i) = \min_{j=i+1}^{n-1} j\ [f(j)\ge t_j]\)。

如果知道这 \(n-1\) 轮的具体情况, \(f\) 就可以在线性时间内处理出来,答案就是 \(n - f(0)\)。

std::set 维护每轮的蛇,\(O(n\log n)\),可以得到70分。

#include <bits/stdc++.h>
#ifdef LOCAL
#define dbg(args...) do std::cerr << "\033[32;1m" << #args << " -> ", err(args); while (0)
#else
#define dbg(...)
#endif
inline void err() { std::cerr << "\033[0m\n"; }
template<class T, class... U>
inline void err(const T &x, const U &... a) { std::cerr << x << ' '; err(a...); }
template <class T>
inline void readInt(T &w) {
  char c, p = 0;
  while (!isdigit(c = getchar())) p = c == '-';
  for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
  if (p) w = -w;
}
template <class T, class... U>
inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }

typedef long long LL;
typedef std::pair<int, int> PII;

constexpr int N(1e6 + 5);
int n, a[N];
void solve() {
  std::set<PII> s;
  for (int i = 1; i <= n; i++) s.insert({a[i], i});
  static int idx[N], t[N];
  for (int i = 1; i <= n; i++) t[i] = 0;
  int ans = 1;
  for (int i = n; i > 1; i--) {
    idx[i] = s.rbegin()->second;
    t[s.begin()->second] = i;
    PII v = *s.rbegin();
    v.first -= s.begin()->first;
    s.erase(--s.end());
    s.erase(s.begin());
    s.insert(v);
  }
  for (int i = 2; i <= n; i++)
    if (t[idx[i]] > ans) ans = i;
  printf("%d\n", ans);
} 
int main() {
  int t;
  readInt(t, n);
  for (int i = 1; i <= n; i++) readInt(a[i]);
  for (solve(); t > 1; t--) {
    int k, x, y;
    readInt(k);
    while (k--) {
      readInt(x, y);
      a[x] = y;
    }
    solve();
  }
  return 0;
}

100分的暂时不会,丢个链接,咕咕咕。

营业日志 2020.11.7 一次信息不对称引发的 CSP2020 T4 讨论 - EntropyIncreaser

标签:std,int,void,readInt,2020,template,inline,CSP
来源: https://www.cnblogs.com/HolyK/p/13956841.html