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\times B < N\) 的(A,B) 都会存在唯一值 C 所以我们只需要对 (A,B) 计数即可
当 \(A\) 值确定时,\(B\) 为 \(⌊\frac{N -1}{A}⌋\) 。所以我们遍历 \(1\) ~ \(N - 1\) 即可。
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上也解释了这道题可以计算 \(N - C\) 的因子数来解决
固定 \(C\),符合条件的二元组 \((A,B)\) 的数目就等于 \(N−C\) 的因子数,而一个正整数的因子数可以通过质因数分解求得。
设:\(n = p_1^{a1}p_2^{a2}...p_n^{an}\),则其因子数为 \(∏_{i = 1}^n(a_i + 1)\)
所以我们就计算 \(1\dots N-1\) 每个数的因子数,然后求和即可。
因为\([1,x]\)范围内的质数个数近似为 \(\frac{x}{\ln x}\),总时间复杂度为 \(O(\frac{N\sqrt{N}}{\log N})\)。
#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
题意:
给 \(N\) 个房间排成一行,房间编号为 \(1,2,...,N\)。目前高桥所在房间为 \(1\) ,现在他想移动到 \(N\) 号房间。
给定 \(K\) 个不相交的区间,而集合 \(S\) 是这 \(K\) 个区间的并集。移动规则如下:
- 高桥在房间 \(i\),可以从集合 \(S\) 中选择一个整数 \(d\),这样可以移动到房间 \(i+d\)。
- 高桥不可以移动到房间以外。
思路:
考虑我们当前处于 \(x\) 位置,我们上一步可能来自哪里?
我们需要检查所有的区间,然后找出对应的区间 \([l,r]\)(如果这样的区间存在的话),这一区间包含了所有能够利用原区间中的步长跳跃到当前位置的位置,也即上一步可能的位置。接下来我们将 \(sum(l,r)\)累加到 \(dp[x]\)上。
因为我们需要快速计算 \(sum(l,r)\),所以实际上我们可以使用前缀和 \(sum[i]\),而非 \(dp[i]\)。
- \(\mathcal{O}(NK)\)
#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
显然,操作足够多次后,一定会开始循环。因为 \(M\leq10^5\),所以循环的长度不超过 \(10^5\),因此我们直接模拟找出循环节即可。
注意:循环节不一定是 x 为起点
- \(\mathcal{O}(M)\)
#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
当我们放一个白石头的时候,会改变多少黑石头的颜色?
对于第一种操作,这是由该列最上面的白石头决定的;对于第二种操作,这是由该行最左边的白石头决定的。
而每种操作的影响是什么呢?第一种操作会影响 \(1\dots X\) 行( \(X\) 是操作的列最上面的白石头所在的行),而第二种操作会影响 \(1\dots X\)列(\(X\)是操作的行最左边的白石头所在的列)。
很自然地想到用线段树来处理。一个储存每行最上面的白石头,另一个储存每列最左边的白石头。对于非叶结点,我们存储区间的最大值。因为我们每次操作相当于一个切割,把所有大于XX的数都变为XX,因此,存储区间最大值,可以让我们很方便地判断当前的切割是否产生了影响。
- \(\mathcal{O}(QlogN)\).
#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;
}
AtCoder Beginner Contest 179 个人题解(C欧拉筛,D前缀和,E循环节,F线段树)的更多相关文章
- KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解
KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200) 题解 哦淦我已经菜到被ABC吊打了. A - Century 首先把当前年 ...
- AtCoder Beginner Contest 179
比赛链接:https://atcoder.jp/contests/abc179/tasks A - Plural Form 题意 给出一个由小写字母组成的单词,如果单词以 $s$ 结尾,在单词的末尾加 ...
- AtCoder Beginner Contest 179 E - Sequence Sum (模拟)
题意:\(f(x,m)\)表示\(x\ mod\ m\),\(A_{1}=1\),而\(A_{n+1}=f(A^{2}_{n},M)\),求\(\sum^{n}_{i=1}A_{i}\). 题解:多算 ...
- AtCoder Beginner Contest 089完整题解
A - Grouping 2 Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement There a ...
- AtCoder Beginner Contest 179 D - Leaping Tak (DP)
题意:给你一个数字\(n\)和\(k\)个区间,\(S\)表示所有区间的并的集合,你目前在\(1\),每次可以从集合中选择一个数字向右移动,问有多少种方法从\(1\)走到\(n\). 题解:我们从1开 ...
- 2018.09.08 AtCoder Beginner Contest 109简要题解
比赛传送门 水题大赛? 全是水题啊!!! T1 ABC333 就是判断是不是两个数都是奇数就行了. 代码: #include<bits/stdc++.h> using namespace ...
- Atcoder Beginner Contest 138 简要题解
D - Ki 题意:给一棵有根树,节点1为根,有$Q$次操作,每次操作将一个节点及其子树的所有节点的权值加上一个值,问最后每个节点的权值. 思路:dfs序再差分一下就行了. #include < ...
- AtCoder Beginner Contest 154 题解
人生第一场 AtCoder,纪念一下 话说年后的 AtCoder 比赛怎么这么少啊(大雾 AtCoder Beginner Contest 154 题解 A - Remaining Balls We ...
- AtCoder Beginner Contest 153 题解
目录 AtCoder Beginner Contest 153 题解 A - Serval vs Monster 题意 做法 程序 B - Common Raccoon vs Monster 题意 做 ...
- AtCoder Beginner Contest 177 题解
AtCoder Beginner Contest 177 题解 目录 AtCoder Beginner Contest 177 题解 A - Don't be late B - Substring C ...
随机推荐
- C#使用SqlSugar操作MySQL数据库实现简单的增删改查
公众号「DotNet学习交流」,分享学习DotNet的点滴. SqlSugar简介 SqlSugar 是一款 老牌 .NET 开源多库架构ORM框架(EF Core单库架构),由果糖大数据科技团队 维 ...
- 【web实验报告】实验二
一.实验目的 通过一个小型网站的开发,掌握JSP基础知识,加深对session,request,response,cookie等对象的理解,掌握其使用方法,进一步深入掌握HTML.CSS和JavaSc ...
- PX4环境安装
1.安装ROS 利用鱼香ros一键安装: wget http://fishros.com/install -O fishros && . fishros 调用的命令为: roscore ...
- Vue3+Vite+ElementPlus管理系统常见问题
本文本记录了使用 Vue3+Vite+ElementPlus 从0开始搭建一个前端工程会面临的常见问题,没有技术深度,但全都是解决实际问题的干货,可以当作是问题手册以备后用.本人日常工作偏后端开发,因 ...
- [ABC265B] Explore
Problem Statement Takahashi is exploring a cave in a video game. The cave consists of $N$ rooms arra ...
- 基于winform(C#)的飞鸟小游戏
本项目是一款基于C# (winform)版本的飞鸟小游戏,是一款益智类游戏 其效果如下图所示 如上图所示为飞鸟游戏的初始化界面: 可以看到游戏包含了四个功能: 启动 注册 登陆 排行榜 启动:是用于开 ...
- 高斯朴素贝叶斯(Gaussian Naive Bayes)原理与实现——垃圾邮件识别实战
朴素贝叶斯(Naive Bayes): 根据贝叶斯定理和朴素假设提出的朴素贝叶斯模型. 贝叶斯定理: 朴素假设(特征条件独立性假设): 代入可知朴素贝叶斯模型计算公式: 因为朴素贝叶斯是用来分类任务, ...
- JSON字符串中获取一个特定字段的值
第一种 import com.google.gson.JsonObject; import com.google.gson.JsonParser; String json="{\" ...
- 密码加密处理MD5与Salt
作用:一般用来加密或者签名(校验和) 特点: MD5算法不可逆如何内容相同无论执行多少次md5生成结果始终是一致 生成结果:始终是一个16进制32位长度字符串 //使用MD5 + salt +hash ...
- SaaS 营销怎么做?几点思考
按大部分 SaaS 公司组织架构,梳理了这 4 大业务部门(产品.市场.销售.服务-客户成功)的职责和客户价值链条.如图: 根据客户价值体验地图,分为两块过程: 客户营销过程 客户成功过程 针对 Sa ...