河南萌新联赛2024第(一)场:河南农业大学

造数

思路:我们可以倒着做,看看 n n n是否可以变成 1 1 1,最优的一定是能除 2 2 2就除 2 2 2,当变为奇数就减 1 1 1,最后还剩 2 2 2的时就之间减 2 2 2

void solve() {
    int n; cin >> n;
    int ans = 0;
    while (true) {
        if (n == 2 || n == 0) break;
        ans ++;
        if (n & 1) n --;
        else n /= 2;
    }
    if (n == 2) ans ++;
    cout << ans << '\n';
}

爱探险的朵拉

思路:比赛时是真的没搞清楚题目意思,其实就是一个基环树森林,找出经过最多点的基环树,先用拓扑排序将环上的点找出来,再 d f s dfs dfs将每一个环用 m a p < i n t , v e c t o r < i n t > > map<int, vector<int>> map<int,vector<int>>都记录下来,建图的时候反着建,因为要找以环上一个点为起点最长的链,其实也不用建图,直接记录后继节点是谁也可以,然后遍历所有基环树更新答案

int a[N], vis[N], d[N], son[N], vi[N];
vector<int> g[N];
int ans, n, idx, cnt;
map<int, vector<int>> mp;


void topsort() {
    queue<int> q;
    for (int i = 1; i <= n; i ++) {
        if (d[i] == 1) {
            q.push(i);
            vis[i] = 1;
        }
    }
    while (q.size()) {
        auto t = q.front();
        q.pop();
        if (vis[son[t]]) continue;
        d[son[t]] --;
        if (d[son[t]] == 1) {
            q.push(son[t]);
            vis[son[t]] = 1;
        }
    }
}
void dfs(int u) {
    if (vi[u]) return ;
    vi[u] = 1;
    mp[idx].push_back(u);
    dfs(son[u]);
};

void dfs1(int u, int d) {
    if (!g[u].size()) {
        cnt = max(cnt, d);
    }
    for (auto v : g[u]) {
        if (vi[v]) continue;
        dfs1(v, d + 1);
    }
};

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        cin >> son[i];
        g[son[i]].push_back(i);
        d[i] ++;
        d[son[i]] ++;
    }
    topsort();
    for (int i = 1; i <= n; i ++) {
        if (d[i] == 2 && !vi[i]) dfs(i), idx ++;
    }
    for (auto [x, y] : mp) {
        int len = 0;
        for (auto j : y) {
            cnt = 0;
            dfs1(j, 0);
            len = max(len, cnt);
        }
        ans = max(ans, (int)y.size() + len);
    }
    cout << ans << '\n';
}

有大家喜欢的零食吗

思路:二分图最大匹配模板题,匈牙利算法,没啥好说的

vector<int> g[N];
int match[N], vis[N], ans;

bool dfs(int u) {
    for (auto v : g[u]) {
        if (vis[v]) continue;
        vis[v] = 1;
        if (!match[v] || dfs(match[v])) {
            match[v] = u;
            return 1;
        }
    }
    return 0;
}

void solve() {
    int n; cin >> n;
    for (int i = 1; i <= n; i ++) {
        int k; cin >> k;
        for (int j = 1, x; j <= k; j ++) {
            cin >> x;
            g[i].push_back(x);
        }
    }
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++) vis[j] = 0;
        if (dfs(i)) ans ++;
    }
    if (ans == n) cout << "Yes" << '\n';
    else cout << "No" << '\n' << n - ans << '\n';
}

小蓝的二进制询问

思路:看着这么大的数据范围,应该是要按每一位求贡献,打表发现从最低位开始,每增加一位周期乘 2 2 2 0 0 0 1 1 1的数量以及总和都乘 2 2 2,每一位的贡献就是周期数 ∗ * 周期的总和 + + +周期余数的和

int get(int s) {
    s ++;
    int sum = 0, zq = 2, gs = 1, zqs = 1;
    for (int j = 0; j < 61; j ++) {
        int x = s / zq, y = s % zq;
        sum += x * zqs % mod;
        sum %= mod;
        sum += max((y - gs), 0ll);
        sum %= mod;
        gs *= 2;
        zq *= 2;
        zqs *= 2;
    }
    return sum;
}

void solve() {
    int t; cin >> t;
    while (t --) {
        int l, r; cin >> l >> r;
        cout << (get(r) - get(l - 1) + mod) % mod << '\n';

    }
}

奇妙的脑回路

太难,以后再补

两难抉择新编

思路:直接暴力求解即可,复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

void solve() {
    int n; cin >> n;
    vector<int> a(n + 1);
    int sum = 0;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum ^= a[i];
    }
    int ans = 0;
    for (int i = 1; i <= n; i ++) {
        sum ^= a[i];
        for (int j = 1; j <= n / i; j ++) {
            ans = max(ans, sum ^ (a[i] + j));
            ans = max(ans, sum ^ (a[i] * j));
        }
        sum ^= a[i];
    }
    cout << ans << '\n';
}

旅途的终点

思路:反悔贪心,先全部把 k k k个神力都用完,放到小根堆里面,当我后面遇见的所消耗的比小根堆里最小的大,我就用小根堆里最小的替换当前的所遇见的

void solve() {
    int n, m, k; cin >> n >> m >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    if (k >= n) {
        cout << n << '\n';
        return ;
    }
    priority_queue<int, vector<int>, greater<int>> Q;
    for (int i = 1; i <= k; i ++) {
        Q.push(a[i]);
    }
    int ans = k;
    for (int i = k + 1; i <= n; i ++) {
        if (Q.size() && Q.top() < a[i]) {
            if (m - Q.top() > 0) {
                ans ++;
                m -= Q.top();
                Q.pop();
                Q.push(a[i]);
            } else if (m - a[i] > 0) {
                ans ++;
                m -= a[i];
            } else break;
        } else {
            if (m - a[i] > 0) {
                ans ++;
                m -= a[i];
            } else break;
        }
    }
    cout << ans << '\n';
}

两难抉择

思路:数组里的最大值大于 1 1 1是乘 n n n,否则加 n n n

void solve() {
    int n; cin >> n;
    vector<int> a(n + 1);
    int mx = 0, sum = 0;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        mx = max(mx, a[i]);
        sum += a[i];
    }
    if (mx == 1) {
        cout << sum - mx + mx + n << '\n';
    } else {
        cout << sum - mx + mx * n << '\n';
    }
}

除法移位

思路:把在可以移动范围内的最大值移到开头,真无语了,这种题

void solve() {
    int n, k; cin >> n >> k;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    int pos = 0, mx = a[1];
    for (int i = n, cnt = 0; i >= 1; i ++) {
        cnt ++;
        if (mx < a[i]) {
            mx = a[i];
            pos = i;
        }
        if (cnt == k) break;
    }
    if (mx == a[1]) cout << 0 << '\n';
    else cout << n - pos + 1 << '\n'; 
}

图上计数(Easy)

思路:将全部边删除,合并乘开两个很接近的数相乘

void solve() {
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        int u, v; cin >> u >> v;
    }
    cout << ((n + 1) / 2) * (n / 2) << '\n';
}
  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值