河南萌新联赛2024第(一)场:河南农业大学
A-造数_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
2 的二进制为 10,对于任意一个数,如 13,其二进制为 1101,可由 10 \(\rightarrow\) 100 \(\rightarrow\) 110 \(\rightarrow\) 1100 \(\rightarrow\) 1101,即 +2,×2,+2,×2,+1,即按照二进制来判断需要用多少次加 2 乘 2 ,最后判断需不需要加 1 即可。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
i64 n;
cin >> n;
int ans = 0;
for (i64 i = 31; i > 0; i --) {
if (ans) ans ++;
if ((n >> i) & 1) {
ans ++;
}
}
cout << ans + (n & 1) << '\n';
return 0;
}
B-爱探险的朵拉_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
前置知识: tarjan缩点+拓扑序。
根据题意可以抽象出就是给你一个有向有环图,然后就是用 tarjan 将环缩成点,用拓扑序跑最长路即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 15;
int n, m, sum, tim, top, s;
int p[maxn], head[maxn], sd[maxn];
int dfn[maxn], low[maxn];
//DFN(u)为节点u搜索被搜索到时的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
int stac[maxn], vis[maxn]; //栈只为了表示此时是否有父子关系
int h[maxn], in[maxn], dist[maxn];
vector<int> g[maxn], ng[maxn];
void tarjan(int x) {
low[x] = dfn[x] = ++tim;
stac[++top] = x; vis[x] = 1;
for (auto v : g[x]) {
if (!dfn[v]) {
tarjan(v);
low[x] = min(low[x], low[v]);
} else if (vis[v]) {
low[x] = min(low[x], low[v]);
}
}
if (dfn[x] == low[x]) {
int y;
while (y = stac[top--]) {
sd[y] = x;
vis[y] = 0;
if (x == y) break;
p[x] += p[y];
}
}
}
int topo() {
queue <int> q;
int tot = 0;
for (int i = 1; i <= n; i++)
if (sd[i] == i && !in[i]) {
q.push(i);
dist[i] = p[i];
}
while (!q.empty())
{
int k = q.front(); q.pop();
for (auto v : ng[k]) {
dist[v] = max(dist[v], dist[k] + p[v]);
in[v]--;
if (in[v] == 0) q.push(v);
}
}
int ans = 0;
for (int i = 1; i <= n; i++)
ans = max(ans, dist[i]);
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i ++)
p[i] = 1;
vector<int> a(n + 1);
vector<pair<int, int>> edge;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
edge.push_back({i, a[i]});
g[i].push_back(a[i]);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
for (auto &[from, to] : edge) {
int x = sd[from], y = sd[to];
if (x != y) {
ng[x].push_back(y);
in[y]++;
}
}
cout << topo() << '\n';
return 0;
}
C-有大家喜欢的零食吗_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
前置知识:二分图最大匹配,匈牙利算法。
将第 i 个小朋友喜欢的第 j 份零食大礼包看成由 i 向 j 连一条边,问左边的 n 个点能最大匹配右边的多少个点,那么这题就是求二分图的最大匹配数,上板子即可。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
struct augment_path {
vector<vector<int> > g;
vector<int> pa; // 匹配
vector<int> pb;
vector<int> vis; // 访问
int n, m; // 两个点集中的顶点数量
int dfn; // 时间戳记
int res; // 匹配数
augment_path(int _n, int _m) : n(_n), m(_m) {
assert(0 <= n && 0 <= m);
pa = vector<int>(n, -1);
pb = vector<int>(m, -1);
vis = vector<int>(n);
g.resize(n);
res = 0;
dfn = 0;
}
void add(int from, int to) {
assert(0 <= from && from < n && 0 <= to && to < m);
g[from].push_back(to);
}
bool dfs(int v) {
vis[v] = dfn;
for (int u : g[v]) {
if (pb[u] == -1) {
pb[u] = v;
pa[v] = u;
return true;
}
}
for (int u : g[v]) {
if (vis[pb[u]] != dfn && dfs(pb[u])) {
pa[v] = u;
pb[u] = v;
return true;
}
}
return false;
}
int solve() {
while (true) {
dfn++;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (pa[i] == -1 && dfs(i)) {
cnt++;
}
}
if (cnt == 0) {
break;
}
res += cnt;
}
return res;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
augment_path ad(n,n);
for(int i = 0;i < n;i ++){
int k;
cin >> k;
for(int j = 0;j < k;j ++){
int x;
cin >> x;
ad.add(i,--x);
}
}
int res = ad.solve();
if(res == n){
cout << "Yes\n";
}else{
cout << "No\n" << n - res << '\n';
}
return 0;
}
D-小蓝的二进制询问_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
对于这种给一个区间求种类数的题目,不难想到前缀和的思想。
现考虑求一个数 x 从 1 到 x 的整数的二进制中的 1 的个数之和。
以 25 为例:
可以看出,对于每一位,画红框的地方是每一位的循环节,第 k 位的循环节长度为 \(2^{k+1}\) ,其中有 \(2^k\) 个 1,所以我们可以按位枚举,计算每一位上总共有多少个循环节和剩下非循环节中 1 的个数,因为这里是从 0 开始计算每一行的长度,所以实际计算时 x 需要加 1,具体计算就是,对于第 i 位:
\[\sum_{i=0}^{60}\frac{x+1}{2^{i+1}}\times2^i+\max((x+1)\%2^{i+1}-2^i,0) \]代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
const i64 mod = 998244353;
void solve() {
i64 l, r;
cin >> l >> r;
auto calc = [&](i64 x)->i64{
i64 res = 0;
x ++;
for (int i = 60; i >= 0; i --) {
i64 y = x / (1ll << (i + 1));
res = (res + y * (1ll << i) % mod) % mod;
res = (res + max(x % (1ll << (i + 1)) - (1ll << i), 0ll)) % mod;
}
return res % mod;
};
cout << (calc(r) - calc(l - 1) + mod) % mod << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
E-奇妙的脑回路_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
代码
F-两难抉择新编_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
对于第 i 个数,直接按 \([1,\frac{n}{i}]\) 的范围枚举两种操作,更新最大值即可。
复杂度 \(O(nlogn)\)
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
i64 ans = 0;
vector<i64> a(n + 1);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
ans ^= a[i];
}
i64 t = ans;
for (int i = 1; i <= n; i ++) {
i64 res = t;
res ^= a[i];
for (int j = 1; j <= n / i; j ++) {
ans = max(ans, res ^ (a[i] + j));
}
for (int j = 1; j <= n / i; j ++) {
ans = max(ans, res ^ (a[i] * j));
}
}
cout << ans << '\n';
return 0;
}
G-旅途的终点_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
遍历 1 到 n ,用最小堆去维护当前最大的 k 个需要消耗的生命力,当枚举到当前所有消耗的生命力之和减去 k 个最大的也大于了 m 就说明无法继续再往下旅游了,注意会爆longlong,开 int128 即可。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
i64 n, m, k;
cin >> n >> m >> k;
using pii = pair<i64, i64>;
vector<i64> a(n + 1);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
__int128 Hp = 0, qhp = 0;
priority_queue<i64, vector<i64>, greater<>> q;
int ans = 0;
for (int i = 1; i <= n; i ++) {
Hp += a[i];
q.push(a[i]);
qhp += a[i];
if (q.size() > k) {
qhp -= q.top();
q.pop();
}
if (Hp - qhp >= m) break;
ans = i;
}
cout << ans << '\n';
return 0;
}
H-两难抉择_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
两种操作都是保证会让原数增大的,所以只要判断下最大值怎么操作即可。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
i64 sum = 0,ma = 0;;
vector<i64> a(n);
for(auto &i : a){
cin >> i;
sum += i;
ma = max(ma,i);
}
sum += max(ma + n,ma * n) - ma;
cout << sum << '\n';
return 0;
}
I-除法移位_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
按定义化成分数形式可得:\(\frac{a_1}{a_2a_3\dots a_n}\),要使该式最大化,即分子越大或者让分母越小,所以只要找到右移(倒序)后小于等于 t 的最大值下标即可。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
struct node {
int v, id;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
i64 n, t;
cin >> n >> t;
vector<node> a(n + 1);
for (int i = 1; i <= n; i ++) {
cin >> a[i].v;
a[i].id = n - i + 1;
}
a[1].id = 0;
sort(a.begin() + 1, a.end(), [](node x, node y) {
if (x.v == y.v) return x.id < y.id;
return x.v > y.v;
});
for (int i = 1; i <= n; i ++) {
auto [v, id] = a[i];
if (id <= t) {
cout << id << '\n';
return 0;
}
}
return 0;
}
J-最大矩阵匹配_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector a(n + 1, vector<bool>(m + 1));
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++) {
char c;
cin >> c;
a[n + 1 - i][j] = c - '0';
}
vector s(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
s[i][j] = a[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
}
}
auto get = [&](int x1, int y1, int x2, int y2)->int{
return s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
};
int ans = 0;
vector dp(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
int k = dp[i - 1][j - 1];
if (k > 0 && a[i][j] && a[i - k + 1][j] && a[i][j - k + 1] && get(i - k + 1, j - k + 1, i, j) == 3 * k - 2)
dp[i][j] = dp[i - 1][j - 1];
if (a[i][j] && a[i - k][j] && a[i][j - k] && get(i - k, j - k, i, j) == 3 * k + 1)
dp[i][j] = dp[i - 1][j - 1] + 1;
ans = max(ans, dp[i][j]);
}
}
cout << ans << '\n';
return 0;
}
K-图上计数(Easy)_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
因为可以删掉任意边又合并任意联通块,所以直接就想象成给你一堆点,合并成两堆使得其乘积最大,即就是两堆点数接近 \(\frac{n}{2}\) 时最大。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
i64 n, m;
cin >> n >> m;
vector g(n + 1, vector<int>());
for (int i = 0; i < m; i ++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
cout << (n / 2)*(n - n / 2) << '\n';
return 0;
}
L-图上计数(Hard)_河南萌新联赛2024第(一)场:河南农业大学 (nowcoder.com)
思路
代码
标签:i64,int,河南,cin,long,2024,vector,萌新,using
From: https://www.cnblogs.com/Kescholar/p/18308368