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";
}
}
}
分类:
其他
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具