河南萌新联赛2024第(二)场:南阳理工学院
河南萌新联赛2024第(二)场:南阳理工学院
A-国际旅行Ⅰ_河南萌新联赛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, q;
cin >> n >> m >> q;
vector<int> a(n);
for (int i = 0; i < n; i ++) {
cin >> a[i];
}
vector g(n, vector<int>());
for (int i = 0; i < m; i ++) {
int u, v;
cin >> u >> v;
u--, v--;
g[u].push_back(v);
g[v].push_back(u);
}
sort(a.begin(), a.end());
while (q--) {
int k;
cin >> k;
cout << a[--k] << '\n';
}
return 0;
}
D-A*BBBB_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)
思路
正解是现B的每一位都相同,然后模拟乘法发现,当B每一位相同时假设为 x,那么就是A乘x,然后B有多少位就往前移多少次,然后再用前缀和进行维护当前位数为多少。
不过 FFT直接秒了
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define L(x) (1 << (x))
const double PI = acos(-1.0);
const int N = 1e7 + 10;
double ax[N], ay[N], bx[N], by[N];
char sa[N / 2], sb[N / 2];
int sum[N];
int x1[N], x2[N];
int revv(int x, int bits) {
int ret = 0;
for (int i = 0; i < bits; i++) {
ret <<= 1;
ret |= x & 1;
x >>= 1;
}
return ret;
}
void fft(double * a, double * b, int n, bool rev) {
int bits = 0;
while (1 << bits < n) ++bits;
for (int i = 0; i < n; i++) {
int j = revv(i, bits);
if (i < j)
swap(a[i], a[j]), swap(b[i], b[j]);
}
for (int len = 2; len <= n; len <<= 1) {
int half = len >> 1;
double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
if (rev) wmy = -wmy;
for (int i = 0; i < n; i += len) {
double wx = 1, wy = 0;
for (int j = 0; j < half; j++) {
double cx = a[i + j], cy = b[i + j];
double dx = a[i + j + half], dy = b[i + j + half];
double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
a[i + j] = cx + ex, b[i + j] = cy + ey;
a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
wx = wnx, wy = wny;
}
}
}
if (rev) {
for (int i = 0; i < n; i++)
a[i] /= n, b[i] /= n;
}
}
int sol(int a[], int na, int b[], int nb, int ans[]) {
int len = max(na, nb), ln;
for (ln = 0; L(ln) < len; ++ln);
len = L(++ln);
for (int i = 0; i < len ; ++i) {
if (i >= na) ax[i] = 0, ay[i] = 0;
else ax[i] = a[i], ay[i] = 0;
}
fft(ax, ay, len, 0);
for (int i = 0; i < len; ++i) {
if (i >= nb) bx[i] = 0, by[i] = 0;
else bx[i] = b[i], by[i] = 0;
}
fft(bx, by, len, 0);
for (int i = 0; i < len; ++i) {
double cx = ax[i] * bx[i] - ay[i] * by[i];
double cy = ax[i] * by[i] + ay[i] * bx[i];
ax[i] = cx, ay[i] = cy;
}
fft(ax, ay, len, 1);
for (int i = 0; i < len; ++i)
ans[i] = (int)(ax[i] + 0.5);
return len;
}
string mul(string sa, string sb) {
int l1, l2, l;
int i;
string ans;
memset(sum, 0, sizeof(sum));
l1 = sa.size();
l2 = sb.size();
for (i = 0; i < l1; i++)
x1[i] = sa[l1 - i - 1] - '0';
for (i = 0; i < l2; i++)
x2[i] = sb[l2 - i - 1] - '0';
l = sol(x1, l1, x2, l2, sum);
for (i = 0; i < l || sum[i] >= 10; i++) {//进位
sum[i + 1] += sum[i] / 10;
sum[i] %= 10;
}
l = i;
while (sum[l] <= 0 && l > 0) l--; // 检索最高位
for (i = l; i >= 0; i--)
ans += sum[i] + '0'; // 倒序输出
return ans;
}
void solve() {
string a, b;
cin >> a >> b;
cout << mul(a, b) << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
E-“好”字符_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)
思路
对于循环同构,我们只需要把 b 字符串再自加一遍就可以解决了。
对于当前某一个字符,我们把除了这个字符之外的都看作*
号,b 中同理,那么问 b 中所有该字符是否和 a 中位置相同就变成了 a 是否是 b 中的一个子串,转化问题之后用字符串哈希或者 kmp 解决就行了。
代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
struct Kmp {
vector<int> next;
void getNext(string p) {
int j = 0, k = -1, n = p.size();
next.resize(n + 1);
next[0] = -1;
while (j < n) {
if (k == -1 || p[j] == p[k]) {
next[++j] = ++k;
} else
k = next[k];
}
}
int kmp(string s, string p) {
int n = s.size(), m = p.size();
int i = 0, j = 0;
while (i < n && j < m) {
if (j == -1 || s[i] == p[j]) {
i ++, j ++;
} else {
j = next[j];
}
}
if (j == m) return i;
else return -1;
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
string a, b;
cin >> a >> b;
vector loca(30, vector<int>());
vector locb(30, vector<int>());
for (int i = 0; i < n; i ++) {
loca[a[i] - 'a'].push_back(i);
locb[b[i] - 'a'].push_back(i);
}
int ans = 0;
for (int i = 0; i < 26; i ++) {
if (loca[i].empty()) continue;
if (loca[i].size() != locb[i].size()) continue;
string sa = string(a.size(), '*'), sb = string(b.size(), '*');
Kmp kmp;
for (auto x : loca[i])
sa[x] = i + 'a';
for (auto x : locb[i])
sb[x] = i + 'a';
sb += sb;
kmp.getNext(sa);
ans += (kmp.kmp(sb, sa) != -1);
}
cout << ans << '\n';
return 0;
}
F-水灵灵的小学弟_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)
思路
诈骗题,两人都是DHY
。
代码
#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;
while(t--){
i64 a,b;
cin >> a >> b;
cout << "DHY\n";
}
return 0;
}
G-lxy的通风报信_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)
思路
处理出 a 支军队两两互相的距离,因为 a 可能有 50 个点,所以不能用状压 dp,但是题中说起点终点不固定,所有只要找到一个总权值最小的方案把所有点连起来就好了,没错,那就是最小生成树了。
代码
#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<string> s(n);
for (auto &i : s)
cin >> i;
int cnt = 0;
vector<pair<int, int>> a, b;
map<pair<int, int>, int> mp;
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++) {
if (s[i][j] == '*') {
a.emplace_back(i, j);
mp[ {i, j}] = cnt ++;
}
}
const int u[] = {1, -1, 0, 0}, v[] = {0, 0, 1, -1};
vector dis(cnt, vector<int>(cnt, -1));
for (int i = 0; i < cnt; i ++) {
auto [sx, sy] = a[i];
vector vis(n, vector<bool>(m));
queue<array<int, 3>> Q;
Q.push({0, sx, sy});
vis[sx][sy] = 1;
dis[i][i] = 0;
while (Q.size()) {
auto [l, x, y] = Q.front();
Q.pop();
if (mp.count({x, y})) {
dis[i][mp[ {x, y}]] = l;
}
for (int k = 0; k < 4; k ++) {
int dx = x + u[k], dy = y + v[k];
if (dx >= 0 && dx < n && dy >= 0 && dy < m && s[dx][dy] != '#' && !vis[dx][dy]) {
Q.push({l + 1, dx, dy});
vis[dx][dy] = 1;
}
}
}
}
for (int i = 0; i < cnt; i ++) {
for (int j = 0; j < cnt; j ++) {
if (dis[i][j] == -1) {
cout << "No\n";
return 0;
}
}
}
vector<array<int, 3>> edge;
for (int i = 0; i < cnt; i ++) {
for (int j = 0; j < cnt; j ++) {
if (i == j) continue;
edge.push_back({dis[i][j], i, j});
}
}
vector<int> fa(cnt);
iota(fa.begin(), fa.end(), 0);
sort(edge.begin(), edge.end());
auto find = [&](auto self, int x)->int{
return fa[x] == x ? x : fa[x] = self(self, fa[x]);
};
int ans = 0, num = 0;
for (int i = 0; i < edge.size(); i ++) {
auto [l, u, v] = edge[i];
u = find(find, u), v = find(find, v);
if (u != v) {
fa[u] = v;
ans += l;
num ++;
}
if (num == cnt - 1) break;
}
cout << ans << '\n';
return 0;
}
H-狼狼的备忘录_河南萌新联赛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;
map<string, set<string>> ans, suf;
for (int i = 0; i < n; i ++) {
string s;
cin >> s;
int k;
cin >> k;
for (int j = 0; j < k; j ++) {
string num;
cin >> num;
if (!suf[s].count(num)) {
for (int p = 0; p < num.size(); p ++) {
if (ans[s].count(num.substr(p))) {
ans[s].erase(num.substr(p));
}
}
ans[s].insert(num);
for (int p = 0; p < num.size(); p ++) {
suf[s].insert(num.substr(p));
}
}
}
}
cout << ans.size() << '\n';
for (auto [id, s] : ans) {
cout << id << ' ' << s.size() << ' ';
for (auto i : s)
cout << i << " \n"[i == *s.rbegin()];
}
return 0;
}
I-重生之zbk要拿回属于他的一切_河南萌新联赛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;
string s;
cin >> s;
int ans = 0;
for(int i = 0;i < s.size();i ++){
if(s.substr(i,5) == "chuan")
ans ++;
}
cout << ans << '\n';
return 0;
}
J-这是签到_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)
思路
按题意计算每 \(i\times i\) 的矩阵行列式,取最小值即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
struct Matrix {
i64 N;
vector<vector<i64>> A;
Matrix() { N = 0;}
Matrix(int n) {
N = n;
A.resize(N + 1);
for (int i = 0; i <= N; i ++)
A[i].resize(N + 1, 0);
}
void init(vector<vector<i64>> a, int n) {
A = a;
N = n;
}
Matrix operator*(const Matrix &b) const {
Matrix res(b.N);
for (int i = 1; i <= b.N; ++i)
for (int j = 1; j <= b.N; ++j)
for (int k = 1; k <= b.N; ++k)
res.A[i][j] = (res.A[i][j] + A[i][k] * b.A[k][j]);
return res;
}
Matrix qpow(i64 k) {
Matrix res(N);
//斐波那契数列初始化
//res.A[1][1] = res.A[1][2] = 1;
//A[1][1] = A[1][2] = A[2][1] = 1;
//单位矩阵
for (int i = 0; i <= N; i ++)
res.A[i][i] = 1;
while (k) {
if (k & 1) res = res * (*this);
(*this) = (*this) * (*this);
k >>= 1;
}
return res;
}
//求行列式
i64 det() {
return DET(A, N);
}
i64 DET(vector<vector<i64>> arr1, int n) {
i64 sum = 0;
//i是第一行的列指标,M是余子式的值,sum是行列式的计算值
if (n == 1)//一阶行列式直接得出结果
return arr1[0][0];
else if (n > 1) {
for (int i = 0; i < n; i++) {
//按照第一行展开
i64 M = Minor(arr1, i, n);
sum += pow(-1, i + 2) * arr1[0][i] * M;
}
}
return sum;
}
i64 Minor(vector<vector<i64>> arr1, int i, int n) {
vector arr2(n + 1, vector<i64>(n + 1));
//以下为构造余子式的过程。
for (int j = 0; j < n - 1; j++) {
for (int k = 0; k < n - 1; k++) {
if (k < i)
arr2[j][k] = arr1[j + 1][k];
else if (k >= i)
arr2[j][k] = arr1[j + 1][k + 1];
}
}
return DET(arr2, n - 1);
//构造完后,余子式是一个新的行列式,返回DET函数进行计算。
}
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector a(10, vector<int>(10));
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
cin >> a[i][j];
i64 ans = INT_MAX >> 1;
Matrix Ma;
for (int i = 1; i <= max(n, m); i ++) {
vector ok(i, vector<i64>(i));
for (int j = 0; j < i; j ++)
for (int k = 0; k < i; k ++)
ok[j][k] = a[j][k];
Ma.init(ok, i);
ans = min(ans, Ma.det());
}
cout << ans << '\n';
return 0;
}