AtCoder Beginner Contest 050
A
输入流是 \(a + b\) 或者 \(a - b\) 。接受输入流然后输出结果。
int a, b; char c; std::cin >> a >> c >> b;
int ans = a + b;
if (c == '+') std::cout << ans << "\n";
else std::cout << ans - 2 * b << "\n";
B
题意:
一场比赛有 \(N\) 个问题,你解决第 \(i\) 个问题需要 \(T_i\) 秒。
有 \(M\) 杯饮料,它可以刺激你的大脑。第 \(i\) 杯饮料可以让第 \(P_i\) 个问题的解决时间变成 \(X_i\) 秒。且不会对其他问题造成影响。
假设你解决所有问题的时间是解决每个问题的时间的和。
回答 \(M\) 个独立询问,询问你喝且仅喝了第 \(i\) 杯饮料后,你需要多少时间解决所有问题。
\(1 \leq N, M \leq 100, 1 \leq T_i, X_i \leq 10^{5}, 1 \leq P_i \leq N\)
题解:
怎么说呢…… 维护一开始的 \(sum = \sum_{i = 1}^{N} T_i\) 。
然后第 \(i(1 \leq i \leq M)\) 个询问的答案是 \(sum - T_{p_i} + X_i\) 。
时间复杂度是显然的 \(O(N + M)\) 。
int N; std::cin >> N;
std::vector<int> T(N + 1);
ll sum = 0;
for (int i = 1; i <= N; i++) {
std::cin >> T[i];
sum += T[i];
}
int M; std::cin >> M;
for (int i = 1; i <= M; i++) {
int P, X; std::cin >> P >> X;
std::cout << sum - T[P] + X << "\n";
}
C
题意:
\(n\) 个人昨天排成一行,但是他们今天忘了他们昨天站在哪里。当然,每个人都记得一个事实:他记得左边的人数减去右边的人数的绝对值。第 \(i\) 个人的这个数值是 \(A_i\) 。
询问昨天共有多少种可能的排列,答案 \(\bmod 10^{9} + 7\) 。
可能存在不正确的信息,导致不存在答案,输出 \(0\) 。
\(1 \leq N \leq 10^{5}, 0 \leq A_i \leq N - 1\)
题解:
设第 \(i\) 个人昨天的位置为 \(P_i\) 。
设昨天第 \(i\) 个人左边有 \(CL_i\) 个人,右边有 \(CR_i\) 个人,于是有:
如果下标没有越界,对 \(i\) 可能出现的位置记录一次贡献。这需要讨论是否 P1 、 P2 相同。
若 \(CL < 0\) 或 \(CR > N\) 或 \(2 \nmid n - 1 + A_i\) ,
或 \(\forall i \in [1, N], v_i \neq 2 \ s.t.\ 2 \mid N\) ,或 $\forall i \in [1, N] \sum [v_i = 2] = N - 2, \sum [b_i = 1] = 1 \ s.t.\ 2 \nmid N $ 。则信息有误。
否则可以分成 \(M = \lfloor \frac{N}{2} \rfloor 2\) 组,每组两个人,可能的排列方案是 \(2\) 。由乘法原理答案为 \(2^{M}\) 。若 \(2 \nmid N\) ,多出来的单人组的乘法贡献是 \(1\) 。
时间复杂度 \(O(N + \log N)\) 。
int N; std::cin >> N;
std::vector<int> A(N + 1), V(N + 1);
for (int i = 1; i <= N; i++) {
std::cin >> A[i];
}
int ok = 1;
for (int i = 1; i <= N; i++) {
int P1 = N - (N - 1 + A[i]) / 2, P2 = N - (N - 1 - A[i]) / 2;
if (P1 > N || P2 < 0 || (N - 1 + A[i]) % 2 == 1) { ok = 0; break; }
V[P1]++, V[P2]++;
if (P1 == P2) V[P1]--;
}
if (N % 2 == 0) for (int i = 1; i <= N; i++) ok &= V[i] == 2;
if (N % 2 == 1) {
int f1 = 0, f2 = 0;
for (int i = 1; i <= N; i++) f1 += (V[i] == 1), f2 += (V[i] == 2);
ok &= (f1 == 1 && f2 == N / 2 * 2);
}
if (!ok) std::cout << 0 << "\n";
else {
int ans = 1, M = N / 2;
while (M--) ans = (ans << 1) % MOD;
std::cout << ans << "\n";
}
D
题意:
给定一个正整数 \(N\) 。找到满足下述条件的 \(u, v(0 \leq u,v \leq N)\) 的对数。
对 \(\forall (u, v)\) , \(\exists a, b(0 \leq a, b)\) 满足
结果 \(\mod 10^{9} + 7\) 输出。
\(1 \leq N \leq 10^{18}\)
题解:
由异或是二进制下不进位的加法,不难有 \(u \leq v\) 。
对 \((u, v)\) 的计数,可以枚举 \(v\) ,然后计算 \(\leq v\) 的所有 \(u\) ,转化为 DP 。
等价于枚举 \(a + b\) ,计算 \(|\{a \subset b\}|\) 。
经典的数位 DP :\(f_{i, j}\) 考虑了 \(i\) 位,\(a + b = j\) 时的答案。
转移为:
进位的三种结果对应 \((a << 1) + 0, (b << 1) + 0\) 、 \((a << 1) + 0, (b << 1) + 1\) 、 \((a << 1) + 1, (b << 1) + 1\) 。
不难滚动优化:
可以离散化或者用 map DP 。
const int MOD = 1E9 + 7;
template <class T,const int P = 2119969 /*314159,451411,1141109,2119969*/ >
struct hashmap {
u64 id[P];
T val[P];
int rec[P]; // del: no many clears
hashmap() { memset(id, -1, sizeof id); }
T get(const u64 &x) const {
for (int i = int(x % P), j = 1; ~id[i]; i = (i + j) % P, j = (j + 2) % P) {
if (id[i] == x)
return val[i];
}
return 0;
}
T& operator [] (const u64 &x) {
for (int i = int(x % P), j = 1; ; i = (i + j) % P, j = (j + 2) % P) {
if (id[i] == x) return val[i];
else if (id[i] == -1llu) {
id[i] = x;
rec[++rec[0]] = i; // del: no many clears
return val[i];
}
}
}
void clear() { // del
while(rec[0])
id[rec[rec[0]]] = -1, val[rec[rec[0]]] = 0, --rec[0];
}
void fullclear() {memset(id, -1, sizeof id); rec[0] = 0; }
};
hashmap<u64> f;
void solve() {
u64 N; std::cin >> N;
f.clear();
f[0] = 1;
std::function<void(u64)> dfs = [&](u64 x) {
if (f.get(x) != 0) return;
if (x >= 0) dfs(x-0 >> 1), f[x] = (f[x] + f[x-0 >> 1]) % MOD;
if (x >= 1) dfs(x-1 >> 1), f[x] = (f[x] + f[x-1 >> 1]) % MOD;
if (x >= 2) dfs(x-2 >> 1), f[x] = (f[x] + f[x-2 >> 1]) % MOD;
};
dfs(N);
std::cout << f[N] << "\n";
}
浙公网安备 33010602011771号