河南萌新聯賽2024第(三)場:河南大學
前言
這場應該算是比較簡單的了,隔壁都有佬 ak 了,咱只有 8t,還是得加訓。
A-圓周率日挑戰_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
Python 最有用的一集。
抄了個 500 行的浮點高精度程式碼爆記憶體了,改了兩個小時也沒過,崩潰。
程式碼
n = int(input())
pi = 31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
arr = []
for i in range(n):
p, a4 = map(int, input().split())
arr.append((abs(p * (10**100) // a4 - pi), p, a4))
arr.sort()
print(arr[0][1], arr[0][2])
B-正規表示式_河南萌新聯賽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;
int ans = 0;
for(int i = 0;i < n;i ++){
int x[4]{};
char c;
cin >> x[0] >> c >> x[1] >> c >> x[2] >> c >> x[3];
bool f = 1;
for(int j = 0;j < 4;j ++) {
if(x[j] > 255)
f = 0;
}
ans += f;
}
cout << ans << '\n';
return 0;
}
C-Circle_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
是個找規律題啊,剛開始被樣例迷惑了還以為 \(2^{n-1}\) 呢,但是一看資料範圍不對啊,結果還是交了一發 wa 了,50 min 後才發現規律 \(\dots\)
官方題解有證明,這裡就說下我的結論好了。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
for (int i = 0; i < t; i ++) {
i64 n;
cin >> n;
if (n)
cout << (n - 1)*(n - 1) + n + 1 << ' ';
else
cout << 1 << ' ';
}
return 0;
}
D-開心消消樂(Right Version)_河南萌新聯賽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;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++)
cin >> a[i];
int ans = 0;
for (int i = 1; i <= n; i ++) {
if (a[i] != a[i - 1] && a[i])
ans ++;
}
cout << ans << '\n';
return 0;
}
E-區間_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
線段樹維護最大欄位和/ 01 串最大連續 1 的個數模板題。
把白色和黑色看成 1/0 兩個數就行了。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define lc u << 1
#define rc u << 1 | 1
const int N = 1e5 + 5;
i64 w[N], n, m, p;
struct Tree { //線段樹
int l, r;
int sum1, lmax1, rmax1, max1;
int sum0, lmax0, rmax0, max0;
int tag, rev;
} tr[N << 2];
void cal_lazy(int fa, int ch) {
int len = tr[ch].r - tr[ch].l + 1;
if (tr[fa].tag == 0) {
tr[ch].tag = 0, tr[ch].rev = 0;
tr[ch].sum0 = tr[ch].lmax0 = tr[ch].rmax0 = tr[ch].max0 = len;
tr[ch].sum1 = tr[ch].lmax1 = tr[ch].rmax1 = tr[ch].max1 = 0;
}
if (tr[fa].tag == 1) {
tr[ch].tag = 1, tr[ch].rev = 0;
tr[ch].sum0 = tr[ch].lmax0 = tr[ch].rmax0 = tr[ch].max0 = 0;
tr[ch].sum1 = tr[ch].lmax1 = tr[ch].rmax1 = tr[ch].max1 = len;
}
if (tr[fa].rev) {
tr[ch].rev ^= 1;
swap(tr[ch].sum1, tr[ch].sum0);
swap(tr[ch].lmax1, tr[ch].lmax0);
swap(tr[ch].rmax1, tr[ch].rmax0);
swap(tr[ch].max1, tr[ch].max0);
}
}
void tag_union(int fa, int ch) {
tr[ch].tag = tr[fa].tag;
tr[ch].rev ^= tr[fa].rev;
}
void init_lazy(int u) {
tr[u].tag = -1;
tr[u].rev = 0;
}
void pushdown(int u) {
if (tr[u].tag != -1 || tr[u].rev != 0) {
cal_lazy(u, lc);
cal_lazy(u, rc);
// tag_union(u, lc);
// tag_union(u, rc);
init_lazy(u);
}
}
void pushup(int u) { //上傳
tr[u].sum1 = tr[lc].sum1 + tr[rc].sum1;
tr[u].sum0 = tr[lc].sum0 + tr[rc].sum0;
tr[u].lmax1 = tr[lc].lmax1 + (tr[lc].sum0 ? 0 : tr[rc].lmax1);
tr[u].rmax1 = tr[rc].rmax1 + (tr[rc].sum0 ? 0 : tr[lc].rmax1);
tr[u].lmax0 = tr[lc].lmax0 + (tr[lc].sum1 ? 0 : tr[rc].lmax0);
tr[u].rmax0 = tr[rc].rmax0 + (tr[rc].sum1 ? 0 : tr[lc].rmax0);
tr[u].max1 = max({tr[lc].max1, tr[rc].max1, tr[lc].rmax1 + tr[rc].lmax1});
tr[u].max0 = max({tr[lc].max0, tr[rc].max0, tr[lc].rmax0 + tr[rc].lmax0});
}
void build(int u, int l, int r) { //建樹
tr[u].l = l, tr[u].r = r;
init_lazy(u);
if (l == r) {
int t = 1;
tr[u] = {l, r, t, t, t, t, t ^ 1, t ^ 1, t ^ 1, t ^ 1, -1, 0};
return ;
}
int mid = (l + r) >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int op) {
if (tr[u].l >= l && tr[u].r <= r) {
int len = tr[u].r - tr[u].l + 1;
if (op == 0) {
tr[u].rev = 0, tr[u].tag = 0;
tr[u].sum0 = tr[u].lmax0 = tr[u].rmax0 = tr[u].max0 = len;
tr[u].sum1 = tr[u].lmax1 = tr[u].rmax1 = tr[u].max1 = 0;
} else if (op == 1) {
tr[u].rev = 0, tr[u].tag = 1;
tr[u].sum0 = tr[u].lmax0 = tr[u].rmax0 = tr[u].max0 = 0;
tr[u].sum1 = tr[u].lmax1 = tr[u].rmax1 = tr[u].max1 = len;
} else {
tr[u].rev ^= 1;
swap(tr[u].sum1, tr[u].sum0);
swap(tr[u].lmax1, tr[u].lmax0);
swap(tr[u].rmax1, tr[u].rmax0);
swap(tr[u].max1, tr[u].max0);
}
return ;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid)
modify(lc, l, r, op);
if (r > mid)
modify(rc, l, r, op);
pushup(u);
}
Tree query(int u, int l, int r) { //區查
if (l <= tr[u].l && tr[u].r <= r)
return tr[u];
int mid = tr[u].l + tr[u].r >> 1;
pushdown(u);
if (r <= mid) return query(lc, l, r);
else if (l > mid) return query(rc, l, r);
else {
Tree res, L = query(lc, l, mid), R = query(rc, mid + 1, r);
res.sum1 = L.sum1 + R.sum1;
res.sum0 = L.sum0 + R.sum0;
res.lmax1 = L.lmax1 + (L.sum0 ? 0 : R.lmax1);
res.rmax1 = R.rmax1 + (R.sum0 ? 0 : L.rmax1);
res.lmax0 = L.lmax0 + (L.sum1 ? 0 : R.lmax0);
res.rmax0 = R.rmax0 + (R.sum1 ? 0 : L.rmax0);
res.max1 = max({L.max1, R.max1, L.rmax1 + R.lmax1});
res.max0 = max({L.max0, R.max0, L.rmax0 + R.lmax0});
return res;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,q;
cin >> n >> q;
build(1,1,n);
while(q--){
int op;
cin >> op;
if(op == 1){
int x;
cin >> x;
modify(1,x,x,2);
}else{
int l,r;
cin >> l >> r;
auto ans = query(1,l,r);
cout << ans.max1 << '\n';
}
}
return 0;
}
F-累加器_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
考慮當 \(x=1,y=1e6\) 時最多隻會加 \(1e6\) 次,那麼先預處理所有發生改變的次數用下字首和即可,然後用 \(1\sim x+y\) 變化次數減去 \(1\sim x\) 變化的就是 \(x\sim x+y\) 變化的次數了。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 2e6;
i64 pre[N + 10];
void solve() {
int x, y;
cin >> x >> y;
cout << pre[x + y] - pre[x] << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int x = 0;
for (int i = 1; i <= N; i ++, x++) {
pre[i] += pre[i - 1];
pre[i] += __builtin_popcount((x + 1)^x);
}
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
G-求值_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
變數有 3 個,不過有限制條件 \(x+y+z=n,0\le x,y,z\) 在,那麼就可以用 \(n-x-y\) 代替 \(z\) 了。
即 \(|x\times A+y\times B+(n-x-y)\times C-W|\),這是個兩元一次的方程,因為絕對值的存在,所以其影像是一個V
的單峰函式,想到單峰函式,那麼自然是我們的三分出場啦。
列舉 \(x\),三分 \(y\) ,每次更新最小值即可。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve() {
i64 a, b, c, n, w;
cin >> a >> b >> c >> n >> w;
auto check = [&](i64 mid, i64 x) {
return abs(x * a + mid * b + (n - mid - x) * c - w);
};
i64 ans = LLONG_MAX >> 1;
for (int i = 0; i <= n; i ++) {
int l = 0, r = n - i;
while (l <= r) {
i64 midl = l + (r - l) / 3;
i64 midr = r - (r - l) / 3;
ans = min({ans, check(midl, i), check(midr, i)});
if (check(midl, i) > check(midr, i))
l = midl + 1;
else
r = midr - 1;
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
H-魔法_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
賽時想複雜了,其實應該還是蠻簡單的,肯定是我太菜了,還得加練。
考慮 dp。
設 \(dp_{i,jk}\) 表示為在 \((i,j)\) 這個位置花費了 \(k\) 次魔法所剩的最大體力值。
轉移方程為:
表示為消耗同次數下從兩個方向轉移過來,當次數大於 0 的時候還需要考慮直接從兩個方向直接用魔法不消耗體力轉移過來:
\(k\) 最大為 \(n+m\) ,即從一直使用魔法達到 \((n,m)\)。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, h;
cin >> n >> m >> h;
vector a(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> a[i][j];
vector dp(n + 1, vector<vector<i64>>(m + 1, vector<i64>(n + m + 1)));
dp[1][1][0] = h;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
for (int k = 0; k <= n + m; k ++) {
dp[i][j][k] = max({dp[i][j][k], dp[i - 1][j][k] - a[i][j], dp[i][j - 1][k] - a[i][j]});
if (k > 0) {
dp[i][j][k] = max({dp[i][j][k], dp[i - 1][j][k - 1], dp[i][j - 1][k - 1]});
}
}
}
}
i64 ans = 0;
for (int i = 0; i < n + m; i ++)
if (dp[n][m][i] > 0) {
ans = i;
break;
}
cout << ans << '\n';
return 0;
}
I-遊戲_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
從 \(1\) 到 n ,無非兩種情況:1、從 \(1\) 走可以透過的邊到達 \(n\) 。2、從 \(1\) 走到 \(k\) 拿到鑰匙後走到 \(n\)。
所以使用兩次 dijkstra ,對全 1 的邊使用一次,然後從 1 走到 k 後再使用一次,兩者取最小值即可。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
struct DIJ {
using i64 = long long;
using PII = pair<i64, i64>;
vector<i64> dis;
vector<vector<PII>> G;
DIJ() {}
DIJ(int n) {
dis.assign(n + 1, 1e18);
G.resize(n + 1);
}
void add(int u, int v, int w) {
G[u].emplace_back(v, w);
}
void dijkstra(int s) {
priority_queue<PII> que;
dis[s] = 0;
que.push({0, s});
while (!que.empty()) {
auto p = que.top();
que.pop();
int u = p.second;
if (dis[u] < p.first) continue;
for (auto [v, w] : G[u]) {
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
que.push({-dis[v], v});
}
}
}
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m,k;
cin >> n >> m >> k;
DIJ dij(n),dij2(n);
for(int i = 0;i < m;i ++){
int u,v,w,st;
cin >> u >> v >> w >> st;
if(st){
dij2.add(u,v,w);
dij2.add(v,u,w);
}
dij.add(u,v,w);
dij.add(v,u,w);
}
dij2.dijkstra(1);
i64 ans = dij2.dis[n];
dij.dijkstra(k);
ans = min(ans,dij2.dis[k]+dij.dis[n]);
cout << (ans == 1e18 ? -1 : ans) << '\n';
return 0;
}
J-keillempkill學姐の卷積_河南萌新聯賽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<i64>(n + 1));
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
cin >> a[i][j];
vector b(m + 1, vector<int>(m + 1));
for (int i = 1; i <= m; i ++)
for (int j = 1; j <= m; j ++)
cin >> b[i][j];
for (int i = 1; i <= m - n + 1; i ++) {
for (int j = 1; j <= m - n + 1; j ++) {
int ans = 0;
for (int l = 1; l + i - 1 <= m && l <= n; l ++) {
for (int r = 1; r + j - 1 <= m && r <= n; r++)
ans += a[l][r] * b[l + i - 1][r + j - 1];
}
cout << ans << " \n"[j == m - n + 1];
}
}
return 0;
}
K-暴食之史萊姆_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
考慮一個史萊姆能吃掉的最大應該為兩側小於它體積的第一個的史萊姆能吃掉的個數 + 1,因為吃掉這個更小的史萊姆後其體積就會變成這個小史萊姆的體積,所以小史萊姆能吃多少,那麼它就能吃多少,在此基礎上還能吃掉小史萊姆。
固定一邊,用單調棧維護一下該邊比當前史萊姆更小的第一個位置即可。
另一邊同理。
程式碼
#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;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++)
cin >> a[i];
stack<int> st;
vector<int> dp1(n + 1), dp2(n + 1);
for (int i = 1; i <= n; i ++) {
while (st.size() && a[st.top()] > a[i]) {
st.pop();
}
if (st.size()) {
dp1[i] = max(dp1[i], dp1[st.top()] + 1);
}
st.push(i);
}
while (st.size())st.pop();
for (int i = n; i >= 1; i --) {
while (st.size() && a[st.top()] > a[i]) {
st.pop();
}
if (st.size()) {
dp2[i] = max(dp2[i], dp2[st.top()] + 1);
}
st.push(i);
}
for (int i = 1; i <= n; i ++)
cout << dp1[i] + dp2[i] << " \n"[i == n];
return 0;
}
L-SSH_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
字串模擬,稍有點 ex,有點天梯賽那味。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m, n, q;
cin >> m >> n >> q;
map<string, string> p;
for (int i = 0; i < m; i ++) {
string a, b;
cin >> a >> b;
p[b] = a;
}
map<string, set<string>> ipuser;
map<string, set<string>> has;
for (int i = 0; i < n; i ++) {
string ip;
int k;
cin >> ip >> k;
for (int j = 0; j < k; j ++) {
string loser, pub;
int t;
cin >> loser >> t;
ipuser[ip].insert(loser);
while (t--) {
cin >> pub;
has[ip + loser].insert(pub);
}
}
}
while (q--) {
string u, ip, pri;
cin >> u >> ip >> pri;
if (ipuser[ip].count(u) && has[ip + u].count(p[pri]))
cout << "Yes\n";
else
cout << "No\n";
}
return 0;
}
M-推箱子_河南萌新聯賽2024第(三)場:河南大學 (nowcoder.com)
思路
賽時應該不想那個 dp的,狀態設計錯了不說,感覺另外兩道還稍簡單點(?
直接暴力 bfs。
同時搜尋箱子和人的位置,當人走到箱子的位置時就和箱子同步移動。
程式碼
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
vector<array<int, 2>> loc(3);
for (auto &[x, y] : loc)
cin >> x >> y;
vector mp(35, vector<int>(35));
int m;
cin >> m;
while (m --) {
int x, y;
cin >> x >> y;
mp[x][y] = 1;
}
const int u[] = {1, -1, 0, 0}, v[] = {0, 0, 1, -1};
queue<array<int, 5>> Q;
const int N = 35;
int vis[N][N][N][N] {};
Q.push({loc[0][0], loc[0][1], loc[2][0], loc[2][1], 0});
vis[loc[0][0]][loc[0][1]][loc[2][0]][loc[2][1]] = 1;
while (Q.size()) {
auto [x1, y1, x3, y3, t] = Q.front();
Q.pop();
if (x3 == loc[1][0] && y3 == loc[1][1]) {
cout << t << '\n';
return 0;
}
for (int i = 0; i < 4; i ++) {
int dx = x1 + u[i], dy = y1 + v[i];
int boxx = x3, boxy = y3;
if (dx > 0 && dx <= 30 && dy > 0 && dy <= 30 && !mp[dx][dy]) {
if (dx == boxx && dy == boxy) {
boxx += u[i], boxy += v[i];
}
if (boxx > 0 && boxx <= 30 && boxy > 0 && boxy <= 30 && !mp[boxx][boxy] && !vis[dx][dy][boxx][boxy]) {
Q.push({dx, dy, boxx, boxy, t + 1});
vis[dx][dy][boxx][boxy] = 1;
}
}
}
}
cout << "-1\n";
return 0;
}