这两天的模拟赛,可以明显地反映出我的弱点——学过的知识点容易忘,即理解差。
所以,我决定将每次模拟赛的知识点先找出,以便我做题。这可能是个好习惯。
30 / 400 30 / 400 30/400
A
0 / 100 0/100 0/100
很明显,这是一道数学题。
先考虑两个皇后在一行,或者一列。比较好像,一行的时候是 n m ( n − 1 ) nm(n-1) nm(n−1),一列的时候是 n m ( m − 1 ) nm(m-1) nm(m−1)。
难推出的是同一斜线上的情况 (没想推,然后废了)。
就像这个图,是一个 4 × 5 4\times5 4×5 的矩形,有三种斜线,各两条,并且反过来也各有两条。
所以, 2 × [ A 2 2 + A 3 2 + . . . . . . + A n 2 × ( m − n + 1 ) + A 3 2 + A 2 2 ] 2\times[A^2_2+A^2_3+......+A^2_n\times(m-n+1)+A^2_3+A^2_2] 2×[A22+A32+......+An2×(m−n+1)+A32+A22]
然后可以化简为 2 ( 3 m − n − 1 ) ( n − 1 ) n 3 \dfrac{2(3m-n-1)(n-1)n}{3} 32(3m−n−1)(n−1)n。
将上面说到的三种情况加起来就是最终的方案数了。
#include <bits/stdc++.h>
using namespace std;
unsigned long long n, m;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
while (cin >> n >> m) {
if (n == 0 && m == 0) return 0;
if (n > m) swap(n, m);
cout << n * m * (n + m - 2) + 2 * (3 * m - n - 1) * (n - 1) * n / 3 << '\n';
}
}
B
ARC175B Parenthesis Arrangement
5 / 100 5/100 5/100
我认为最难的一道。
B × 2 ≥ A B\times2\ge A B×2≥A 那么用操作一。
否则用操作二。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 5e5 + 10;
int n, a, b;
string s;
int l, r, m;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> a >> b >> s;
for (int i = 0; i < 2 * n; ++i) {
if (s[i] == ')') {
if (m) m--;
else l++, m++;
}
else m++;
}
if (n) r = m / 2;
if (l < r) swap(l, r);
if (b * 2 <= a) cout << (l + r) * b;
else cout << r * a + (l - r) * b;
}
C
15 / 100 15/100 15/100
甚至,我这道题刷过。然后考场打废了。
一个 b f s bfs bfs 直接搞定了,记录药水的价值,在更新时取最小值。说实话,它就是 s p f a spfa spfa。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e2 + 10;
struct node {int x, y, e;};
int n, m, q;
int sx, sy, ex, ey;
int me[maxn][maxn];
bool g[maxn][maxn], vis[maxn][maxn];
int dis[maxn][maxn];
int dir[5][2] = {{0, 0}, {1, 0}, {0, 1}, {0, -1}, {-1, 0}};
void bfs() {
vis[sx][sy] = 1;
queue<node> q;
q.push({sx, sy, 0});
while(!q.empty()) {
int x = q.front().x, y = q.front().y, e = q.front().e;
q.pop();
if(x == ex && y == ey) {cout << "Yes" << '\n';return;}
if(me[x][y] > 0 && e < me[x][y]) e = me[x][y];
for(int i = 1; i <= 4; i++) {
int nx = x + dir[i][0], ny = y + dir[i][1];
if(vis[nx][ny] == 0 || e - 1 > dis[nx][ny]) {
if(g[nx][ny] && e > 0) {
dis[nx][ny] = e - 1;
vis[nx][ny] = 1;
q.push({nx, ny, e - 1});
}
}
}
}
cout << "No\n";
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
char c;
cin >> n >> m;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cin >> c;
if (c == '#') continue;
g[i][j] = 1;
if(c == 'S') sx = i, sy = j;
else if(c == 'T') ex = i, ey = j;
}
}
cin >> q;
for(int i = 1, x, y, w; i <= q; i++) {
cin >> x >> y >> w;
me[x][y] = w;
}
bfs();
return 0;
}
D
10 / 100 10/100 10/100
很简单的最短路加 d f s dfs dfs 求数量。
d f s dfs dfs 部分原来写错了。对于 d i s a > d i s b dis_a > dis_b disa>disb 的情况连一条边,然后 d f s dfs dfs 找到去终点有多少条路即可。
// 最短路计数 luogu yc
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 5e3 + 10, inf = 0x7f7f7f7f, mod = 100003;
int n, m;
struct node {
int v, w;
};
vector<node> e[maxn << 1];
struct edge{
int to, dis;
bool operator < (const edge &o) const{return dis > o.dis;}
};
int dis[maxn];
bool vis[maxn];
void dijkstra(int s) {
memset(vis, 0, sizeof vis);
memset(dis, 0x7f, sizeof dis);
priority_queue<edge> q;
q.push({s, 0});
dis[s] = 0;
while (!q.empty()) {
int u = q.top().to;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto ed: e[u]) {
int v = ed.v, w = ed.w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
q.push({v, dis[v]});
}
}
}
}
int ans;
void dfs(int u, int fa) {
if (u == 2) {
ans++;
return;
}
for (auto ed: e[u]) if (ed.v != fa) {
if (dis[ed.v] < dis[u]) dfs(ed.v, u);
}
}
void init() {
for (int i = 0; i < maxn; ++i) e[i].clear();
ans = 0;
}
void solve() {
init();
for (int i = 1, u, v, w; i <= m; ++i) {
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
dijkstra(2);
if (dis[2] == inf) {
cout << 0 << '\n';
return;
}
dfs(1, 0);
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
while (cin >> n) {
if (n == 0) exit(0);
cin >> m;
solve();
}
}