比赛链接
A题
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e6 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
char s[N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> s[i];
}
int ans = 0;
for (int i = 1; i <= n - 2; i++)
{
if (s[i] == '#' && s[i + 1] == '.' && s[i + 2] == '#')
ans++;
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
B题
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e6 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
struct Point
{ // 点
double x, y;
Point() {}
Point(double x, double y) : x(x), y(y) {}
Point operator+(Point B) { return Point(x + B.x, y + B.y); }
Point operator-(Point B) { return Point(x - B.x, y - B.y); }
} p[N];
double Distance(Point A, Point B)
{ // 两点之间的欧氏距离
return sqrtl((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
void solve()
{
cin >> n;
p[0] = {0, 0};
for (int i = 1; i <= n; i++)
{
cin >> p[i].x >> p[i].y;
}
double ans = 0;
n++;
for (int i = 0; i < n; i++)
{
int j = (i + 1) % n;
ans += Distance(p[i], p[j]);
}
cout << fixed << setprecision(8) << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
C题
思路
其实就是从外圈到内圈的局部旋转,注意取模,每个圈最多旋转3次。
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e3 + 5, M = 1e6 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
char a[N][N], b[N][N];
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> a[i][j];
}
}
for (int k = 1; k <= n / 2; k++)
{
int num = k % 4;
vector<char> v[4];
for (int j = k + 1; j <= n - k; j++)
{
v[0].push_back(a[k][j]);
}
for (int i = k + 1; i <= n - k; i++)
{
v[1].push_back(a[i][n - k + 1]);
}
for (int j = n - k; j >= k + 1; j--)
{
v[2].push_back(a[n - k + 1][j]);
}
for (int i = n - k; i >= k + 1; i--)
{
v[3].push_back(a[i][k]);
}
vector<char> op[4];
for (int i = 0; i < 4; i++)
{
op[(i + num) % 4] = v[i];
}
int idx = 0;
for (int j = k + 1; j <= n - k; j++)
{
b[k][j] = op[0][idx++];
}
idx = 0;
for (int i = k + 1; i <= n - k; i++)
{
b[i][n - k + 1] = op[1][idx++];
}
idx = 0;
for (int j = n - k; j >= k + 1; j--)
{
b[n - k + 1][j] = op[2][idx++];
}
idx = 0;
for (int i = n - k; i >= k + 1; i--)
{
b[i][k] = op[3][idx++];
}
vector<int> ji;
ji.push_back(a[k][k]);
ji.push_back(a[k][n - k + 1]);
ji.push_back(a[n - k + 1][n - k + 1]);
ji.push_back(a[n - k + 1][k]);
vector<int> kk(4);
for (int i = 0; i < 4; i++)
{
kk[(i + num) % 4] = ji[i];
}
b[k][k] = kk[0];
b[k][n - k + 1] = kk[1];
b[n - k + 1][n - k + 1] = kk[2];
b[n - k + 1][k] = kk[3];
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << b[i][j];
}
cout << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
D题
思路
预处理出每一个字符的前缀和与后缀和,最后遍历一遍直接计算即可。
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 5, M = 1e6 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
int pre[N][26], nxt[N][26];
string s;
void solve()
{
cin >> s;
n = s.size();
s = "#" + s;
for (int i = 1, j = n; i <= n; i++, j--)
{
int op1 = s[i] - 'A';
int op2 = s[j] - 'A';
for (int k = 0; k < 26; k++)
{
pre[i][k] = pre[i - 1][k];
nxt[j][k] = nxt[j + 1][k];
}
pre[i][op1]++, nxt[j][op2]++;
}
int ans = 0;
for (int i = 2; i < n; i++)
{
for (int k = 0; k < 26; k++)
{
int low = pre[i - 1][k];
int high = nxt[i + 1][k];
ans += (low * high);
}
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
E题
思路
注意到, n n n最大为100,强度的和最大值为1500。因为有三组,所以每一组强度的和最大值为500。
我们令 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前 i i i个已经分配完成,第 1 1 1组的强度为 j j j,第 2 2 2组的强度为 k k k时需要执行换队操作的最小数量。
状态转移方程为:
d p [ i + 1 ] [ j + b [ i + 1 ] ] [ k ] = m i n ( d p [ i + 1 ] [ j + b [ i + 1 ] ] [ k ] , d p [ i ] [ j ] [ k ] + ( a [ i + 1 ] ! = 1 ) ) dp[i + 1][j + b[i + 1]][k] = min(dp[i + 1][j + b[i + 1]][k], dp[i][j][k] + (a[i + 1] != 1)) dp[i+1][j+b[i+1]][k]=min(dp[i+1][j+b[i+1]][k],dp[i][j][k]+(a[i+1]!=1))
d p [ i + 1 ] [ j ] [ k + b [ i + 1 ] ] = m i n ( d p [ i + 1 ] [ j ] [ k + b [ i + 1 ] ] , d p [ i ] [ j ] [ k ] + ( a [ i + 1 ] ! = 2 ) ) dp[i + 1][j][k + b[i + 1]] = min(dp[i + 1][j][k + b[i + 1]], dp[i][j][k] + (a[i + 1] != 2)) dp[i+1][j][k+b[i+1]]=min(dp[i+1][j][k+b[i+1]],dp[i][j][k]+(a[i+1]!=2))
d p [ i + 1 ] [ j ] [ k ] = m i n ( d p [ i + 1 ] [ j ] [ k ] , d p [ i ] [ j ] [ k ] + ( a [ i + 1 ] ! = 3 ) ) dp[i + 1][j][k] = min(dp[i + 1][j][k], dp[i][j][k] + (a[i + 1] != 3)) dp[i+1][j][k]=min(dp[i+1][j][k],dp[i][j][k]+(a[i+1]!=3))
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e2 + 5, M = 5e2 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
int a[N], b[N], dp[N][M][M];
void solve()
{
cin >> n;
int sum = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
sum += b[i];
}
if (sum % 3 != 0)
{
cout << -1 << endl;
return;
}
memset(dp, inf, sizeof dp);
dp[0][0][0] = 0, sum /= 3;
for (int i = 0; i < n; i++)
{
for (int j = 0; j <= sum; j++)
{
for (int k = 0; k <= sum; k++)
{
if (dp[i][j][k] == inf)
continue;
if (j + b[i + 1] <= sum)
dp[i + 1][j + b[i + 1]][k] = min(dp[i + 1][j + b[i + 1]][k], dp[i][j][k] + (a[i + 1] != 1));
if (k + b[i + 1] <= sum)
dp[i + 1][j][k + b[i + 1]] = min(dp[i + 1][j][k + b[i + 1]], dp[i][j][k] + (a[i + 1] != 2));
dp[i + 1][j][k] = min(dp[i + 1][j][k], dp[i][j][k] + (a[i + 1] != 3));
}
}
}
if (dp[n][sum][sum] == inf)
{
cout << -1 << endl;
}
else
cout << dp[n][sum][sum] << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
F题
思路
对于所有的查询,我们考虑倒着进行离线操作。先用 F l o y d Floyd Floyd进行一次预处理求出所有的 d i s t [ x ] [ y ] dist[x][y] dist[x][y],即点到点 y y y的最短距离。
之后根据查询的条件,不断将新的边加到图中,并根据新边用 F l o y d Floyd Floyd进行 n 2 n^2 n2的更新操作。
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e2 + 5, M = 1e6 + 5;
const int inf = 1e14;
int n, m, q;
int g[N][N];
struct edge
{
int a, b, c;
};
vector<edge> v;
struct query
{
int id, x, y;
};
vector<query> op;
void solve()
{
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
g[i][j] = inf;
}
}
for (int i = 1, a, b, c; i <= m; i++)
{
cin >> a >> b >> c;
g[a][b] = c;
g[b][a] = c;
v.push_back({a, b, c});
}
for (int i = 1, id, x, y; i <= q; i++)
{
cin >> id >> x;
if (id == 1)
{
int a = v[x - 1].a;
int b = v[x - 1].b;
int c = v[x - 1].c;
g[a][b] = inf;
g[b][a] = inf;
}
y = 0;
if (id == 2)
cin >> y;
op.push_back({id, x, y});
}
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
}
}
vector<int> ans;
for (int num = q - 1; num >= 0; num--)
{
if (op[num].id == 1)
{
int x = op[num].x;
int a = v[x - 1].a;
int b = v[x - 1].b;
int c = v[x - 1].c;
g[a][b] = min(g[a][b], c);
g[b][a] = min(g[b][a], c);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
g[i][j] = min(g[i][j], g[i][a] + g[a][j]);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
g[i][j] = min(g[i][j], g[i][b] + g[b][j]);
}
}
}
else
{
int x = op[num].x;
int y = op[num].y;
if (g[x][y] >= inf / 2)
ans.push_back(-1);
else
ans.push_back(g[x][y]);
}
}
reverse(ans.begin(), ans.end());
for (int val : ans)
{
cout << val << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}