Atcoder Beginner Contest 423
A
入机验证题。
答案 \(\lfloor{\frac{X}{1000 + C}}\rfloor\)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int X, C;
signed main() {
scanf ("%lld %lld", &X, &C);
printf ("%lld\n", X / (1000 + C) * 1000);
return 0;
}
B
找前缀后缀 0 的个数即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, a[105], cntl, cntr;
signed main() {
scanf ("%lld", &n);
for (int i = 1; i <= n; i++)
scanf ("%lld", &a[i]);
for (int i = 1; i <= n; i++) {
if (!a[i])
cntl++;
else
break;
}
for (int i = n; i >= 1; i--) {
if (!a[i])
cntr++;
else
break;
}
if (cntl + cntr > n)
printf ("0\n");
else
printf ("%lld\n", n + 1 - cntl - cntr - 2);
return 0;
}
C
最优的方法肯定是从 \(R\) 开始两边走到底来关,那么原本关着的要被操作两次,原本开着的只会被操作一次。
#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int MAXN = 5e5 + 10;
int n, R, lpos, rpos, ans, L[MAXN];
signed main() {
scanf ("%lld %lld", &n, &R);
for (int i = 1; i <= n; i++)
scanf ("%lld", &L[i]);
lpos = 0;
for (; lpos < R; lpos++) {
if (L[lpos + 1] == 0)
break;
}
rpos = n;
for (; rpos > R; rpos--) {
if (L[rpos] == 0)
break;
}
for (; lpos < R; lpos++) {
if (!L[lpos + 1])
ans++;
else
ans += 2;
}
for (; rpos > R; rpos--) {
if (!L[rpos])
ans++;
else
ans += 2;
}
printf ("%lld\n", ans);
return 0;
}
D
我草我怎么老是拿道题大脑空白。
小学奥数之前学过一个很神奇的东西叫做最优统筹,同理可以考虑这题。具体的,人数不是问题,只要时间最短即可,那么按照用餐时间从小到大用优先队列维护,下一批人不够就弹出队头增加空位,如果当前时间没到下一批的时间就直接跳到下一批的进入时间即可,
#include <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
using namespace std;
char buf[1 << 23], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 23, stdin), p1 == p2) ? EOF : *p1++)
inline int read() {
int res = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
f = ch == '-' ? -1 : 1, ch = getchar();
while (isdigit(ch))
res = res * 10 + (ch ^ 48), ch = getchar();
return res * f;
}
const int N = 3e5 + 10;
int n, k, tim;
int A[N], B[N], C[N];
priority_queue<pii, vector<pii>, greater<pii>> q;
signed main() {
n = read(), k = read();
for (int i = 1; i <= n; i++)
A[i] = read(), B[i] = read(), C[i] = read();
for (int i = 1; i <= n; i++) {
while (k < C[i]) {
pii t = q.top();
q.pop();
k += t.second;
tim = t.first;
}
tim = max(tim, A[i]);
printf ("%lld\n", tim);
q.push(make_pair(B[i] + tim, C[i]));
k -= C[i];
}
return 0;
}
E
考虑每个 \(a_i\) 对答案的贡献,那么就需要可考虑包含其的区间个数。在 \(<i\) 的一边选择心仪的左端点,\(>i\) 的一边选择心仪的右端点,你发现总共有 \((r - i + 1) \times (i - l + 1)\) 个区间包含了 \(a_i\),那么对答案的贡献就是 \((r - i + 1) \times (i - l + 1) \times a_i\),拆开之后就是 \(a_i \times i \times (l + r) - a_i \times i^2 + a_i \times (r - l + 1 - lr)\),那么只需要记 \(a_i,a_i\times i^2, a_i \times i\) 的前缀和即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10;
int n, q;
int a[N], sum1[N], sum2[N], sum3[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum1[i] = sum1[i - 1] + a[i];
sum2[i] = sum2[i - 1] + a[i] * i * i;
sum3[i] = sum3[i - 1] + a[i] * i;
}
for (int _ = 1; _ <= q; _++) {
int L, R; cin >> L >> R;
cout << (sum3[R] - sum3[L - 1]) * (L + R) - (sum2[R] - sum2[L - 1]) + (sum1[R] - sum1[L - 1]) * (R - L + 1 - L * R) << '\n';
}
return 0;
}
F
看到恰好的第一时间脑袋空空???
其实第一时间没看到恰好两字(
考虑二项式反演,记 \(g_k\) 表示至少 \(k\) 个 \(a_i\) 整除 \([1,Y]\) 内的同一个数的次数,\(f_k\) 表示恰好 \(k\) 个 \(a_i\) 整除 \([1,Y]\) 内的同一个数的次数。
关键在于如何求 \(g_i\)。
我们发现最终确定的年份与所选择的 \(a_i\) 的最小公倍有关,同时选择的 \(a_i\) 个数小于 \(m\) 一定没有贡献。那么求出最小公倍数 \(val\) 之后,如果 \(val \mid Y\),则至少就会有 \(m\) 个 \(a_i\) 满足条件。但是求最小公倍的时候会爆 longlong,那么 \(val > Y\) 直接舎掉即可。现在我们可以来算 \(g_i\) 了:\(g_i = \lfloor{\frac{Y}{\operatorname{lcm}\limits_{x \in \left|S\right|}}}\rfloor\),那么最后有 \(ans = \sum{(-1)^{\operatorname{popcount(st) - m}}\binom{\operatorname{popcount(st)}}{m}g_i}\)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 25, S = (1 << 20) + 10;
int n, m, Y, ans, a[N], C[N][N];
void initCombineNum() {
C[0][0] = 1;
for (int i = 1; i <= 20; i++) {
C[i][0] = 1;
for (int j = 1; j <= 20; j++)
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
signed main() {
scanf ("%lld", &n);
scanf ("%lld", &m);
scanf ("%lld", &Y);
for (int i = 1; i <= n; i++)
scanf ("%lld", &a[i]);
initCombineNum();
for (int st = 0; st < (1 << n); st++) {
int popc = __builtin_popcountll(st), val = 1;
if (popc >= m) {
bool flag = true;
for (int i = 1; i <= n; i++) {
if ((st >> (i - 1)) & 1) {
int t = __gcd(a[i], val);
if (1.0 * val / t > 1.0 * Y / a[i]) {
flag = false;
break;
}
val = val / t * a[i];
}
}
if (flag)
ans += (((popc - m) & 1) ? -1 : 1) * C[popc][m] * (Y / val);
}
}
printf ("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号