2025-10-04 HETAO CSP-S复赛集训营模拟赛-003 Ⅰ
A.布布
原题链接:布布 - 核桃OJ
分析:inn[i],outt[i]中i表示i号乘客!!!弄清了这个,基本上是迎刃而解,剩余小问题放在注释里了。很……的题。
正解:
#include <bits/stdc++.h>
using namespace std;
const int N = 5000005;
int T, n, op, a, x;
int inn[N], outt[N]; //inn[i]与outt[i]分别存储了i乘客进站与出站的次数
int cnt[N]; //cnt[i]存储了某一位乘客经过i号站点的次数
vector<int> buc[N]; //对于buc[i]中存储了i乘客所有进入或出去的站点
int main(){freopen("station.in", "r", stdin);freopen("station.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> T;while (T--){for (int i = 1; i <= n; i++){buc[i].clear();inn[i] = 0;outt[i] = 0;}cin >> n;for (int i = 1; i <= n; i++){cin >> op >> a >> x;if (op == 1){inn[a]++;}if (op == 2){outt[a]++;}buc[a].push_back(x);}int ans = 0;for (int i = 1; i <= n; i++){ans += abs(inn[i] - outt[i]); //找到不配对的int maxn = -1; //maxn表示某个站点实际出现的最多次数for (auto v : buc[i]){ //找出现次数最多的站cnt[v]++;maxn = max(maxn, cnt[v]);}ans += 2 * max(0, maxn - max(inn[i], outt[i]));//max(inn[i], outt[i])表示理论上最少需要的站点访问次数//maxn - max(inn[i], outt[i])表示额外访问次数//每次额外访问都是往返,算两次,所以*2for (auto v : buc[i]){cnt[v]--;}}cout << ans << '\n';}
}
B.最大公约数
原题链接:最大公约数 - 核桃OJ
分析:观察发现,对于每个i(1≤i≤k),选上所有i的倍数一定不劣,但是我产生了一个很烫的疑问:那如果所有i的倍数又恰好是ni(n∈N+)的倍数怎么办?这不是一个问题,因为既然所有的倍数都恰好为ni(n∈N+)的倍数,那么无论删去谁,删去几个,都无济于事。所以,直接写代码就行了。(这几天做题,线性筛的处理方式:j+=i这种在统计倍数时真的常用,要熟记。以前做ZYZOJ的比赛,喜欢考类似快读read的模拟,都是实现上的小Trick)。
正解:
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
int T, n, k, buc[N];
int a;
int main(){freopen("gcd.in", "r", stdin);freopen("gcd.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> T;while (T--){memset(buc, 0, sizeof(buc)); //多测不清空是要爆0的!cin >> n >> k;for (int i = 1; i <= n; i++){cin >> a;buc[a]++;}for (int i = 1; i <= k; i++){int cnt = 0; //是i倍数的子序列长度int gcdd = 0; //子序列gcdfor (int j = i; j <= n; j += i){cnt += buc[j];if (buc[j]) //注意判非空gcdd = __gcd(gcdd, j);elsegcdd = __gcd(gcdd, 0);}if (gcdd == i){cout << cnt << " ";}elsecout << 0 << " ";}cout << '\n';}
}