2025牛客寒假算法基础集训营2
A. 一起奏响历史之音!
题意:判断7个数里有没有出现4或7.
点击查看代码
void solve() {
int a[7];
for (int i = 0; i < 7; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < 7; ++ i) {
if (a[i] == 4 || a[i] == 7) {
std::cout << "NO\n";
return;
}
}
std::cout << "YES\n";
}
B. 能去你家蹭口饭吃吗
题意:给你一个数组,问最大的满足小于
排序后取中位数减一即可。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
std::cout << a[n / 2] - 1 << "\n";
}
C. 字符串外串
题意:字符串的可爱度定义为最大的
关于构造方式,可以"abcd..xyz"
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
if (n < m + 1 || n > m + 1 + 25) {
std::cout << "NO\n";
return;
}
std::string t;
for (int i = 0; i < 26; ++ i) {
t += (char)('a' + i);
}
std::cout << "YES\n";
std::string s;
while (s.size() + 26 <= m) {
s += t;
}
s = s + t.substr(0, m - (int)s.size());
s = t.substr(0, n - (int)s.size()) + s;
std::cout << s << "\n";
}
D. 字符串里串
题意:字符串的可爱度定义为最大的
对于任意长度为
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
std::vector<std::vector<int> > pos(26);
for (int i = 0; i < n; ++ i) {
pos[s[i] - 'a'].push_back(i);
}
auto check = [&](int len) -> bool {
for (int i = 0; i + len - 1 < n; ++ i) {
if (i != pos[s[i] - 'a'][0] || i + len - 1 != pos[s[i + len - 1] - 'a'].back()) {
return true;
}
}
return false;
};
int l = 1, r = n - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
if (!check(l)) {
std::cout << 0 << "\n";
} else {
std::cout << l << "\n";
}
}
E. 一起走很长的路
题意:给你一个数字,
如果我们给前面的加一,它会使得后面的数更容易满足条件,减一则可能导致本来满足结果小于后面的数了。那么我们应该只进行加一操作。设
点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)
struct Node {
int l, r;
i64 max;
};
const int N = 2e5 + 5;
i64 a[N], sum[N];
struct SegmentTree {
std::vector<Node> tr;
SegmentTree(int _n) {
tr.assign(_n << 2, {});
build(1, _n);
}
void pushup(int u) {
tr[u].max = std::max(tr[ls].max, tr[rs].max);
}
void build(int l, int r, int u = 1) {
tr[u] = {l, r};
if (l == r) {
tr[u].max = a[l] - sum[l - 1];
return;
}
int mid = l + r >> 1;
build(l, mid, ls); build(mid + 1, r, rs);
pushup(u);
}
i64 query(int l, int r, int u = 1) {
if (l <= tr[u].l && tr[u].r <= r) {
return tr[u].max;
}
int mid = umid;
if (r <= mid) {
return query(l, r, ls);
} else if (l > mid) {
return query(l, r, rs);
}
return std::max(query(l, r, ls), query(l, r, rs));
}
};
void solve() {
int n, q;
std::cin >> n >> q;
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
SegmentTree tr(n);
while (q -- ) {
int l, r;
std::cin >> l >> r;
if (l == r) {
std::cout << 0 << "\n";
} else {
i64 max = tr.query(l + 1, r);
std::cout << std::max(0ll, max + sum[l - 1]) << "\n";
}
}
}
F. 起找神秘的数!
题意:求
我们发现,与运算是取
点击查看代码
void solve() {
i64 l, r;
std::cin >> l >> r;
std::cout << r - l + 1 << "\n";
}
G. 一起铸最好的剑!
题意:求
特判
点击查看代码
void solve() {
i64 n, m;
std::cin >> n >> m;
i64 ans = 1, d = std::abs(n - m);
if (m == 1) {
std::cout << 1 << "\n";
return;
}
using i128 = __int128;
auto abs = [&](i128 x) -> i128 {
return x >= 0 ? x : -x;
};
i128 x = m * m;
for (int i = 2; x <= n + d; x *= m, ++ i) {
if (abs(n - x) < d) {
d = abs(n - x);
ans = i;
}
}
std::cout << ans << "\n";
}
H. 一起画很大的圆!
题意:在一个矩形的边上找三个点,使得可以让边经过这三个点的圆半径最大。
假设三个点是
点击查看代码
void solve() {
int a, b, c, d;
std::cin >> a >> b >> c >> d;
if (b - a >= d - c) {
std::cout << a << " " << c << "\n";
std::cout << a + 1 << " " << c << "\n";
std::cout << b << " " << c + 1 << "\n";
} else {
std::cout << a << " " << c << "\n";
std::cout << a << " " << c + 1 << "\n";
std::cout << a + 1 << " " << d << "\n";
}
}
I. 一起看很美的日落!
题意:给你一棵树,每个节点有点权。一个连通块的值定义为连通块里的任意两个点异或和的和。求树上所有连通块值的和。
对于位运算,我们尽可能考虑按位求和。
这题明显是树形dp,那么我们考虑如何计算贡献。记
其中
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<std::vector<int> > adj(n);
for (int i = 1; i < n; ++ i) {
int u, v;
std::cin >> u >> v;
-- u, -- v;
adj[u].push_back(v);
adj[v].push_back(u);
}
std::vector dp(n, std::array<Z, 30>{});
std::vector f(n, std::array<std::array<Z, 2>, 30>{});
std::vector<Z> cnt(n);
Z ans = 0;
auto dfs = [&](auto self, int u, int fa) -> void {
cnt[u] = 1;
for (int i = 0; i < 30; ++ i) {
f[u][i][~a[u] >> i & 1] = 0;
f[u][i][a[u] >> i & 1] = 1;
}
for (auto & v : adj[u]) {
if (v == fa) {
continue;
}
self(self, v, u);
for (int i = 0; i < 30; ++ i) {
dp[u][i] += dp[u][i] * cnt[v] + dp[v][i] * cnt[u] +
(f[u][i][0] * f[v][i][1] + f[u][i][1] * f[v][i][0]) * (Z)(1 << i);
f[u][i][0] += f[u][i][0] * cnt[v] + f[v][i][0] * cnt[u];
f[u][i][1] += f[u][i][1] * cnt[v] + f[v][i][1] * cnt[u];
}
cnt[u] += cnt[u] * cnt[v];
}
for (int i = 0; i < 30; ++ i) {
ans += dp[u][i];
}
};
dfs(dfs, 0, -1);
std::cout << ans * 2 << "\n";
}
J. 数据时间?
题意:统计某一天的三个时间段有多少人。
用
点击查看代码
void solve() {
int n;
std::string y, m;
std::cin >> n >> y >> m;
if (m.size() == 1) {
m = "0" + m;
}
std::string l[5] = {"07:00:00", "11:00:00", "22:00:00", "00:00:00", "18:00:00"};
std::string r[5] = {"09:00:00", "13:00:00", "23:59:59", "01:00:00", "20:00:00"};
std::array<std::set<std::string>, 3> s{};
for (int i = 0; i < n; ++ i) {
std::string id, a, b;
std::cin >> id >> a >> b;
if (a.substr(0, 4) != y || a.substr(5, 2) != m) {
continue;
}
if ((b >= l[2] && b <= r[2]) || (b >= l[3] && b <= r[3])) {
s[2].insert(id);
} else if (b >= l[1] && b <= r[1]) {
s[1].insert(id);
} else if ((b >= l[0] && b <= r[0]) || (b >= l[4] && b <= r[4])) {
s[0].insert(id);
}
}
for (int i = 0; i < 3; ++ i) {
std::cout << s[i].size() << " \n"[i == 2];
}
}
K. 可以分开吗?
题意:求每个
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::string> s(n);
for (int i = 0; i < n; ++ i) {
std::cin >> s[i];
}
const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
std::set<std::pair<int, int> > set;
std::vector vis(n, std::vector<int>(m));
auto dfs = [&](auto self, int x, int y) -> void {
if (s[x][y] == '0') {
set.insert({x, y});
return;
}
vis[x][y] = 1;
for (int i = 0; i < 4; ++ i) {
int nx = x + dx[i], ny = y + dy[i];
if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny]) {
continue;
}
self(self, nx, ny);
}
};
int ans = n * m;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
if (!vis[i][j] && s[i][j] == '1') {
set.clear();
dfs(dfs, i, j);
ans = std::min(ans, (int)set.size());
}
}
}
std::cout << ans << "\n";
}
M. 那是我们的影子
题意:有一个
首先判断无解的情况,发现第
然后考虑怎么填,根据之前的发现,第
知道有多少排列合法后,后面每列的填法就是看有多少个问号,乘起来就行了。
点击查看代码
const int mod = 1e9 + 7;
void solve() {
int n;
std::cin >> n;
std::vector<std::string> s(3);
for (int i = 0; i < 3; ++ i) {
std::cin >> s[i];
}
std::vector<std::set<int> > nums(3);
for (int j = 0; j < n; ++ j) {
if (j + 2 < n) {
std::vector<int> cnt(10);
for (int i = 0; i < 3; ++ i) {
for (int k = j; k < j + 3; ++ k) {
if (s[i][k] != '?' && ++ cnt[s[i][k] - '0'] > 1) {
std::cout << 0 << "\n";
return;
}
}
}
}
std::vector<int> cnt(10);
for (int i = 0; i < 3; ++ i) {
if (s[i][j] != '?') {
if (++ cnt[s[i][j] - '0'] > 1) {
std::cout << 0 << "\n";
return;
}
nums[j % 3].insert(s[i][j] - '0');
}
}
}
if (nums[0].size() > 3 || nums[1].size() > 3 || nums[2].size() > 3) {
std::cout << 0 << "\n";
return;
}
std::vector<int> st(3);
for (int i = 0; i < 3; ++ i) {
for (auto & x : nums[i]) {
st[i] |= 1 << x;
}
}
std::vector<int> p(9);
std::iota(p.begin(), p.end(), 1);
i64 ans = 0;
do {
int flag = 1;
for (int i = 0; i < 3 && flag; ++ i) {
for (int j = 0; j < 3; ++ j) {
if (s[i][j] != '?' && s[i][j] - '0' != p[i * 3 + j]) {
flag = 0;
break;
}
}
}
if (!flag) {
continue;
}
for (int i = 0; i < 3; ++ i) {
int x = (1 << p[i]) + (1 << p[i + 3]) + (1 << p[i + 6]);
if ((x & st[i]) != st[i]) {
flag = 0;
break;
}
}
ans += flag;
} while (next_permutation(p.begin(), p.end()));
i64 v[4] = {1, 1, 2, 6};
for (int i = 3; i < n; ++ i) {
int cnt = (s[0][i] == '?') + (s[1][i] == '?') + (s[2][i] == '?');
ans = (ans * v[cnt]) % mod;
}
std::cout << ans << "\n";
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!