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\) 内部的某个加法操作所受的影响可以分为三个部分:
- 内部乘法的影响
- \(\prod_{j = i + 1}^k multi_j\)
- 调用\(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