AtCoder Beginner Contest 179 个人题解(C欧拉筛,D前缀和,E循环节,F线段树)
补题链接:Here
A - Plural Form
字符串,末尾有 s
的加es
,不然加 s
.
B - Go to Jail
输入的时候判断一下是否连续相等即可
C - A x B + C (math,欧拉筛)
题意:请问能找到多少组 (A,B,C)= N
.
思路一:对于使得 (A,B)
都会存在唯一值 C
所以我们只需要对 (A,B)
计数即可
当
AC 代码
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
int n;
cin >> n;
ll cnt = 0;
for (int i = 1; i <= n; ++i) cnt += (n - 1) / i;
cout << cnt << "\n";
return 0;
}
思路二:
另外在 CP wiki上也解释了这道题可以计算
固定
设:
所以我们就计算
因为
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using namespace std;
int main() {
int n;
cin >> n;
vector<int> primes = {2, 3, 5, 7, 11, 13};
for (int i = 17; i <= n - 1; i += 2) {
bool is_prime = true;
for (int j = 0; primes[j] * primes[j] <= i; ++j) {
if (i % primes[j] == 0) {
is_prime = false;
break;
}
}
if (is_prime)
primes.emplace_back(i);
}
int ans = 0;
for (int i = 1; i < n; ++i) {
int k = i;
int fac = 1;
for (int j = 0; primes[j] * primes[j] <= k; ++j) {
if (k % primes[j] == 0) {
int cnt = 0;
while (k % primes[j] == 0)
cnt++, k /= primes[j];
fac *= (cnt + 1);
}
}
if (k != 1) fac *= 2;
ans += fac;
}
cout << ans;
}
思路三:
欧拉筛,令f[i]为a*b=i的方案数,
f[i]的前缀和就是a*b<=i的方案数.
又因为题目中a*b+c的c必须>=1,那么我们输出f[n-1]即可,原理是留了一个1给c.
AC 代码
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll maxn = 2e6 + 7;
ll f[maxn], n;
signed main() {
ios_base::sync_with_stdio(false), cin.tie(0);
for (int i = 1; i < maxn; ++i)
for (int j = i; j < maxn; j += i) f[j] += 1;
for (int i = 1; i < maxn; ++i) f[i] += f[i - 1];
cin >> n;
cout << f[n - 1] << "\n";
return 0;
}
D - Leaping Tak
题意:
给
给定
- 高桥在房间
,可以从集合 中选择一个整数 ,这样可以移动到房间 。 - 高桥不可以移动到房间以外。
思路:
考虑我们当前处于
我们需要检查所有的区间,然后找出对应的区间
因为我们需要快速计算
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
const ll mod = 998244353;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
int n, k;
cin >> n >> k;
vector<pair<int, int>> v(k);
for (int i = 0; i < k; ++i) cin >> v[i].first >> v[i].second;
vector<ll> sum(n + 1, 0);
sum[1] = 1;
for (int i = 2; i <= n; ++i) {
ll cur = 0;
for (int j = 0; j < k; ++j) {
// 如果这个区间的起点大于 i 就不可能 i 是由这个点移动到的了
if (v[j].first >= i) continue;
int l = max(1, i - v[j].second);
int r = i - v[j].first;
cur += sum[r] - sum[l - 1];
}
cur %= mod;
sum[i] = (sum[i - 1] + cur + mod) % mod;
}
cout << (sum[n] - sum[n - 1] + mod) % mod;
return 0;
}
E - Sequence Sum
显然,操作足够多次后,一定会开始循环。因为
注意:循环节不一定是 x 为起点
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
int main() {
ios_base::sync_with_stdio(false), cin.tie(0);
ll n, x, m;
cin >> n >> x >> m;
map<ll, ll> mp;
int idx = 0;
vector<ll> path;
do {
mp[x] = idx++;
path.emplace_back(x);
x = x * x % m;
} while (!mp.count(x));
int start = mp[x];
int len = idx - start;
ll sum = 0;
// 循环节之和
for (int i = start; i < idx; ++i) sum += path[i];
ll ans = 0;
if (n < start) // 可能未进入循环节就结束累加了
for (int i = 0; i < n; ++i) ans += path[i];
else {
for (int i = 0; i < start; ++i) ans += path[i];
ll loop = (n - start) / len;
ans += loop * sum;
ll res = (n - start) % len; // 多余一节
for (int i = 0; i < res; ++i) ans += path[start + i];
}
cout << ans << "\n";
return 0;
}
F - Simplified Reversi
当我们放一个白石头的时候,会改变多少黑石头的颜色?
对于第一种操作,这是由该列最上面的白石头决定的;对于第二种操作,这是由该行最左边的白石头决定的。
而每种操作的影响是什么呢?第一种操作会影响
很自然地想到用线段树来处理。一个储存每行最上面的白石头,另一个储存每列最左边的白石头。对于非叶结点,我们存储区间的最大值。因为我们每次操作相当于一个切割,把所有大于XX的数都变为XX,因此,存储区间最大值,可以让我们很方便地判断当前的切割是否产生了影响。
.
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
#define MAXN 200005
#define lson (idx << 1)
#define rson (idx << 1 | 1)
using namespace std;
typedef long long ll;
struct Node {
int l, r, hi, lazy = 0;
};
struct SegTree {
Node s[MAXN << 2];
void calc(int idx) { s[idx].hi = max(s[lson].hi, s[rson].hi); }
void pushdown(int idx) {
if (s[idx].lazy) {
for (int i = lson; i <= rson; ++i) {
if (s[i].hi > s[idx].lazy) {
s[i].hi = s[idx].lazy;
s[i].lazy = s[idx].lazy;
}
}
}
s[idx].lazy = 0;
}
void build(int idx, int l, int r, vector<int> &a) {
s[idx].l = l, s[idx].r = r;
if (l == r) {
s[idx].hi = a[l];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid, a);
build(rson, mid + 1, r, a);
calc(idx);
}
void update(int idx, int l, int r, int x) {
if (s[idx].hi <= x)
return;
if (s[idx].l >= l && s[idx].r <= r) {
s[idx].hi = x;
s[idx].lazy = x;
return;
}
pushdown(idx);
int mid = (s[idx].l + s[idx].r) >> 1;
if (l <= mid)
update(lson, l, r, x);
if (mid + 1 <= r)
update(rson, l, r, x);
calc(idx);
}
int query(int idx, int l, int r) {
if (s[idx].l >= l && s[idx].r <= r)
return s[idx].hi;
pushdown(idx);
int ans = 0;
int mid = (s[idx].l + s[idx].r) >> 1;
if (l <= mid)
ans = max(ans, query(lson, l, r));
if (mid + 1 <= r)
ans = max(ans, query(rson, l, r));
return ans;
}
};
int main() {
int n, q;
cin >> n >> q;
vector<int> col(n + 1, n), row(n + 1, n);
col[n] = 1, row[n] = 1;
SegTree C, R;
C.build(1, 1, n, col);
R.build(1, 1, n, row);
ll ans = (ll)(n - 2) * (n - 2);
for (int i = 0; i < q; ++i) {
int t, x;
cin >> t >> x;
if (t == 1) {
int hi = C.query(1, x, x);
ans -= hi - 2;
R.update(1, 1, hi, x);
C.update(1, x, x, 1);
} else {
int hi = R.query(1, x, x);
ans -= hi - 2;
C.update(1, 1, hi, x);
R.update(1, x, x, 1);
}
}
cout << ans;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 全程不用写代码,我用AI程序员写了一个飞机大战
2020-04-06 动态规划之最小编辑距离