Firefly Cup (1st Zrnstsr Cup)

F. Pull

题目大意

抽卡。每抽有a%的概率出货,c发不出货之后每发的出货的概率都会提高b%。求出货的抽数期望

解题思路

最坏的情况下就是一直抽到概率为100%,次数是(100 - a + b - 1) / b + c,之后从后往前开始递推,小于c发就是p/100,否则就加上对应的b%增幅即可(注意要和100%取小),当前次数的答案就是1加上失败的概率乘多抽一次的期望,最后的答案就是第一抽的时候的期望

代码实现

#include <bits/stdc++.h>

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int a, b, c;
        std::cin >> a >> b >> c;

        int maxn = (100 - a + b - 1) / b + c;
        std::vector<double> dp(maxn + 1, 1.0);

        for (int i = maxn - 1; i >= 1; i--) {
            double p;
            if (i <= c) {
                p = a / 100.0;
            } else {
                p = std::min((a + (i - c) * b) / 100.0, 1.0);
            }
            dp[i] += (1.0 - p) * dp[i + 1];
        }

        std::cout << std::fixed << std::setprecision(6) << dp[1] << "\n";
    }
}

D. Greedy Counting

题目大意

设数组a的贪心子序列为“碰见一个大的就选”所得到的子序列,求a的所有子数组的贪心子序列长度之和。

解题思路

右侧第一个比x大的数字显然能让存在x的子序列长度再增加,于是先用单调栈预处理出x右侧第一个比x大的数字,再从右侧dp,记录用当前位置开始的子序列能贡献出多少最后求和即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int n;
        std::cin >> n;

        std::vector<int> a(n);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
        }

        std::vector<int> stk, next(n, n);
        for (int i = n - 1; i >= 0; i--) {
            while (!stk.empty() && a[stk.back()] <= a[i]) {
                stk.pop_back();
            }
            if (!stk.empty()) {
                next[i] = stk.back();
            }
            stk.push_back(i);
        }

        i64 ans = 0;
        std::vector<i64> dp(n);
        for (int i = n - 1; i >= 0; i--) {
            if (next[i] == n) {
                dp[i] = n - i;
            } else {
                dp[i] = (n - i) + dp[next[i]];
            }
            ans += dp[i];
        }

        std::cout << ans << "\n";
    }
}

E. Ever Forever

题目大意

维护一个字符串集合,每次加入或删除时都要输出有几对字符串满足一个字符串是另一个的后缀。

解题思路

字符串哈希存入所有字符的后缀,之后暴力模拟比较即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
const int MOD1 = 1e9 + 7, MOD2 = 1e9 + 9;

class StringHash {
   public:
    int P1, P2;
    std::vector<u64> h1, h2, p1, p2;

    StringHash() {
        std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
        P1 = std::uniform_int_distribution<int>(128, 10000)(rng);
        P2 = std::uniform_int_distribution<int>(128, 10000)(rng);
    }

    template <typename Sequence>
    void build(const Sequence& seq) {
        int n = seq.size();
        h1.resize(n + 1, 0);
        h2.resize(n + 1, 0);
        p1.resize(n + 1, 1);
        p2.resize(n + 1, 1);
        for (int i = 1; i <= n; i++) {
            h1[i] = (h1[i - 1] * P1 + seq[i - 1]) % MOD1;
            h2[i] = (h2[i - 1] * P2 + seq[i - 1]) % MOD2;
            p1[i] = (p1[i - 1] * P1) % MOD1;
            p2[i] = (p2[i - 1] * P2) % MOD2;
        }
    }

    std::pair<u64, u64> get(int l, int r) {
        u64 hash1 = (h1[r] - h1[l - 1] * p1[r - l + 1] % MOD1 + MOD1) % MOD1;
        u64 hash2 = (h2[r] - h2[l - 1] * p2[r - l + 1] % MOD2 + MOD2) % MOD2;
        return {hash1, hash2};
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::set<std::pair<u64, u64>> st;
    std::map<std::pair<u64, u64>, int> mp;

    int n;
    std::cin >> n;

    StringHash sh;
    i64 ans = 0;

    while (n--) {
        std::string op, s;
        std::cin >> op >> s;

        sh.build(s);
        std::vector<std::pair<u64, u64>> suff;

        int len = s.size();
        for (int i = 0; i < len; i++) {
            suff.push_back(sh.get(i + 1, len));
        }

        std::pair<u64, u64> hash = suff[0];

        if (op == "+") {
            int A = mp[hash], B = 0;
            for (auto x : suff) {
                mp[x]++;
                B += st.count(x);
            }
            st.insert(hash);
            ans += A + B;
        } else {
            int A = mp[hash], B = 0;
            for (auto x : suff) {
                mp[x]--;
                B += st.count(x);
            }
            st.erase(hash);
            ans -= (A + B - 2);
        }

        std::cout << ans << " \n"[n == 0];
    }
}

L. Fyreflies

题目大意

有一个未知数组a,询问x可以得到数组中其他元素和x的曼哈顿距离和,用至多40次询问找到a的其中一个元素

解题思路

显然这是一个下凸函数,因此只需要二分出一个让导数变化的位置即可

代码实现

#include <bits/stdc++.h>

int main() {
    int t;
    std::cin >> t;

    while (t--) {
        int n;
        std::cin >> n;

        int dist1;
        std::cout << "? 1" << std::endl;
        std::cin >> dist1;

        int l = 1, r = 1e5, x = 1, dist2 = dist1;
        while (l <= r) {
            int mid = (l + r) / 2;
            std::cout << "? " << mid << std::endl;
            std::cin >> dist1;
            if (dist2 - dist1 == (mid - x) * n) {
                l = mid + 1;
                x = mid;
                dist2 = dist1;
            } else {
                r = mid - 1;
            }
        }
        
        std::cout << "! " << r << std::endl;
    }
}

I. Ciallo

题目大意

求由字符串s的所有前缀和字符串t的所有后缀拼接而成的不同非空字符串的个数。

解题思路

容斥一下,用全部的减去重复的即可

代码实现

#include <bits/stdc++.h>

int main() {
    std::ios::sync_with_stdio(fabs);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        std::string s, t;
        std::cin >> s >> t;

        std::map<char, int> mp1, mp2;
        for (auto ch : s) {
            mp1[ch]++;
        }
        for (auto ch : t) {
            mp2[ch]++;
        }

        int ans = (s.size() + 1) * (t.size() + 1) - 1;
        for (char ch = 'a'; ch <= 'z'; ch++) {
            ans -= mp1[ch] * mp2[ch];
        }

        std::cout << ans << "\n";
    }
}

G. DSU

题目大意

求一个合理的merge序列使得路径压缩的并查集f数组满足题设

解题思路

除了自环显然不能再有其他环,否则就无解。观察f数组发现合并操作不能让两个并查集变动,把两棵树的根合并即可,因此要自下而上构建整棵树,可以用拓扑排序实现

代码实现

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    int t;
    std::cin >> t;

    while (t--) {
        int n;
        std::cin >> n;

        std::vector<std::vector<int>> g(n, std::vector<int>());
        std::vector<int> in(n);
        for (int u = 0, v; u < n; u++) {
            std::cin >> v;
            if (u == v) {
                continue;
            }
            g[u].push_back(v);
            in[v]++;
        }

        std::queue<int> que;
        for (int i = 0; i < n; i++) {
            if (!in[i]) {
                que.push(i);
            }
        }

        std::vector<std::array<int, 2>> opt;
        while (!que.empty()) {
            int u = que.front();
            que.pop();
            for (auto v : g[u]) {
                opt.push_back({u, v});
                if (!--in[v]) {
                    que.push(v);
                }
            }
        }
        
        if (std::count(in.begin(), in.end(), 0) == n) {
            std::cout << opt.size() << "\n";
            for (auto [u, v] : opt) {
                std::cout << u << " " << v << "\n";
            }
        } else {
            std::cout << -1 << "\n";
        }
    }
}
posted @   udiandianis  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
  1. 1 山海不可平 CMJ
山海不可平 - CMJ
00:00 / 00:00
An audio error has occurred.

纯音乐,请欣赏

点击右上角即可分享
微信分享提示