AtCoder Beginner Contest 367

A - Shout Everyday (abc367 A)

题目大意

高桥从A睡到 B,如果在 C时,他醒着,他则会对章鱼烧发癫,问他今天是否发癫。

解题思路

由于只有24小时,直接枚举 AB,看看是否遍历到 C即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int a, b, c;
cin >> a >> b >> c;
bool ok = true;
for (; a != b; a = (a + 1) % 24) {
if (a == c) {
ok = false;
break;
}
}
if (ok)
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


B - Cut .0 (abc367 B)

题目大意

给定一个小数,将末尾零删掉,如果小数部分删掉则把小数部分删掉。

解题思路

按照题意模拟即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
string s;
cin >> s;
while (s.back() == '0')
s.pop_back();
if (s.back() == '.')
s.pop_back();
cout << s << '\n';
return 0;
}


C - Enumerate Sequences (abc367 C)

题目大意

输出所有符合要求的数组a,满足

  • a的和是 k的倍数
  • ai的范围是 1ri

解题思路

dfs枚举所有的情况即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
vector<int> a(n);
for (auto& i : a)
cin >> i;
vector<int> ans(n);
auto dfs = [&](auto&& self, int pos) -> void {
if (pos == n) {
if (accumulate(ans.begin(), ans.end(), 0) % k == 0) {
for (auto i : ans)
cout << i << " ";
cout << '\n';
}
return;
}
for (int i = 1; i <= a[pos]; ++i) {
ans[pos] = i;
self(self, pos + 1);
}
};
dfs(dfs, 0);
return 0;
}


D - Pedometer (abc367 D)

题目大意

环形湖的n个点,给定 ai表示从第 i个点顺时针走到第 i+1个点的时间。

问对数 (s,t),满足从 s顺时针 t,使得其时间是m的倍数。

解题思路

考虑st的情况,其实就可以假象在一条数轴上,从左走到右的时间,这个时间其实就是 i=st1ai,这里可以预处理出 ai的前缀和,其实就是换算成下标 posi,那么从 st,就是 postposs,其差值是 m的倍数 ,这个就意味着post%m==poss%m。所以统计 (s,t)的对数,其实就是统计 posi%m的个数问题。

枚举 t,然后考虑有多少的 st符合要求,而符合要求的 s就是满足 post%m==poss%m,所以用 cnt维护poss%m的个数,那么枚举 t,符合要求的 s的数量就是 cnt[post%m]

而对于,考虑 s>t的情况 可以把环形解成链再翻倍一下,即12,3,4,1,2,3,4,后面的1的位置就是pos1+posi,即偏移了一圈的距离。然后在枚举第二圈的t时,cnt维护的是第一圈的t+1第一圈的 nposi%m的数量。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> a(n);
for (auto& x : a)
cin >> x;
vector<int> cnt(m, 0);
LL ans = 0;
LL presum = 0;
for (int i = 0; i < n; ++i) {
ans += cnt[presum % m];
cnt[presum % m]++;
presum += a[i];
}
LL sum = presum;
presum = 0;
for (int i = 0; i < n; ++i) {
cnt[presum % m]--;
ans += cnt[sum % m];
sum += a[i];
presum += a[i];
}
cout << ans << '\n';
return 0;
}


E - Permute K times (abc367 E)

题目大意

给定数组x,a,进行 k次操作。

每次操作,求数组 bi=axi,然后 b=a

k次操作后的数组 a

解题思路

题目其实可以抽象成,给定基环内向森林,点有点权。问从每个点出发,走了k步后的点的点权。

其中边是ixi,点权 ai

由于图是固定的,问第 k步后到达的点,预处理倍增数组 run[i][j]表示从点 j出发走了 2i步后到达的点。

然后对于每个点用倍增数组求 k次后的结果即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
LL k;
cin >> n >> k;
vector<vector<int>> run(64, vector<int>(n));
for (int i = 0; i < n; i++) {
int v;
cin >> v;
--v;
run[0][i] = v;
}
vector<int> a(n);
for (auto& x : a)
cin >> x;
for (int i = 1; i < 64; i++) {
for (int j = 0; j < n; j++) {
run[i][j] = run[i - 1][run[i - 1][j]];
}
}
for (int i = 0; i < n; i++) {
LL cnt = k;
int cur = i;
for (int j = 0; j < 64; j++) {
if (cnt & (1LL << j)) {
cur = run[j][cur];
}
}
cout << a[cur] << " \n"[i == n - 1];
}
return 0;
}


F - Rearrange Query (abc367 F)

题目大意

给定两个数组a,b,回答 q个问题。

每个问题给定 l,r,L,R,问 a[l..r]能否通过重排,等于 b[L..R]

解题思路

如果a[l..r]能通过重排 b[L..R],首先得 rl==RL,然后看每个数的出现次数是否一致。显然这判断代价很大。

一个计算代价小的的必要条件是suma[l..r]==sumb[L..R],但不是充分条件,会有误判的概率,会被精心构造的数据卡掉。

因为我们只要求数量相等,如果我们事先对所有数进行一个随机映射,这个误判的概率将极大减小。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
unsigned rnd() {
static unsigned A = 1 << 16 | 3, B = 33333331, C = 2341;
return C = A * C + B;
}
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, q;
cin >> n >> q;
vector<LL> a(n);
vector<LL> b(n);
map<int, LL> tr;
for (auto& x : a) {
cin >> x;
if (tr.find(x) == tr.end()) {
tr[x] = rnd();
}
}
for (auto& x : b) {
cin >> x;
if (tr.find(x) == tr.end()) {
tr[x] = rnd();
}
}
auto presum = [&](vector<LL>& a) {
int n = a.size();
vector<LL> s1(n + 1);
for (int i = 0; i < n; ++i) {
s1[i + 1] = (s1[i] + tr[a[i]]);
}
return s1;
};
auto sa1 = presum(a);
auto sb1 = presum(b);
auto sum = [&](vector<LL>& s, int l, int r) { return (s[r] - s[l - 1]); };
auto check = [&](int l, int r, int L, int R) {
auto SA = sum(sa1, l, r);
auto SB = sum(sb1, L, R);
return SA == SB;
};
while (q--) {
int l, r, L, R;
cin >> l >> r >> L >> R;
if (r - l == R - L && check(l, r, L, R)) {
cout << "Yes" << '\n';
} else {
cout << "No" << '\n';
}
}
return 0;
}


G - Sum of (XOR^K or 0) (abc367 G)

题目大意

给定n个数的数组a,问 a所有的2n1个非空子序列b的价值和。

一个序列 b的价值定义如下:

  • 如果个数是 m的倍数,则价值是 (bi)k
  • 否则价值是 0

解题思路

只会m=1k=1

神奇的代码


posted @   ~Lanly~  阅读(776)  评论(8编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2017-08-17 JZOJ.5286【NOIP2017模拟8.16】花花的森林
点击右上角即可分享
微信分享提示