2021牛客寒假算法基础集训营4
2021牛客寒假算法基础集训营4
A 九峰与签到题
题目有歧义, 白wa4发
int main() {
IOS; cin >> m >> n;
rep (i, 1, m) {
int x; cin >> x >> op;
if (op[0] == 'A') ++a[x];
else ++b[x];
if (a[x] < b[x]) c[x] = 1;
}
bool f = 0;
rep (i, 1, n) if (!c[i]) cout << i << ' ', f = 1;
if (!f) cout << -1;
return 0;
}
B 武辰延的字符串
kmp
int lens, lent, f[N], extend[N];
char s[N], t[N];
void kmp(char* t, int lent) { //t从1开始
int j = 0, k = 2;
while (j + 2 <= lent && t[j + 1] == t[j + 2]) ++j;
f[2] = j; f[1] = lent;
for (int i = 3, p = k + f[k] - 1; i <= lent; ++i, p = k + f[k] - 1)
if (i + f[i - k + 1] - 1 < p) f[i] = f[i - k + 1];
else {
j = max(0, p - i + 1);
while (j + i <= lent && t[j + 1] == t[i + j]) ++j;
f[i] = j; k = i;
}
}
void ex_kmp(char *s, char *t, int lens, int lent) { //s, t下标都是从1开始
int j = 0, k = 1;
while (j + 1 <= min(lens, lent) && s[j + 1] == t[j + 1]) ++j;
extend[1] = j;
for (int i = 2, p = k + extend[k] - 1; i <= lens; ++i, p = k + extend[k] - 1)
if (i + f[i - k + 1] - 1 < p) extend[i] = f[i - k + 1];
else {
j = max(0, p - i + 1);
while (j + i <= lens && j + 1 <= lent && t[j + 1] == s[i + j]) ++j;
extend[i] = j; k = i;
}
}
int main() {
IOS; cin >> t + 1 >> s + 1;
lent = strlen(t + 1); lens = strlen(s + 1);
kmp(t, lent); ex_kmp(s, t, lens, lent);
ll ans = 0;
rep (i, 1, extend[1]) ans += extend[i + 1];
cout << ans;
return 0;
}
E 九峰与子序列
哈希一下, 在倒着dp就行了
const int N = 5e6 + 5, p = 131;
int n, m, _, k, cas;
char s[N];
ull has[N], bas[N];
ll f[N];
int main() {
cin >> n >> (s + 1); bas[0] = f[0] = 1;
for (k = 1; s[k]; ++k) has[k] = has[k - 1] * p + s[k], bas[k] = bas[k - 1] * p;
for (int i = 1; i <= n; ++i) {
cin >> s + 1; ull cur = 0;
for (m = 1; s[m]; ++m) cur = cur * p + s[m];
for (int j = k - m; j >= 0; --j) if (has[j] * bas[m - 1] + cur == has[j + m - 1]) f[j + m - 1] += f[j];
}
cout << f[k - 1];
return 0;
}
F 魏迟燕的自走棋
一件装备最多有两个合适的人选, 肯定是按照权值从高到低找
用并查集表示在一个集合内的所有数可以选一次, 原先所有的人f[i] = i都可以选一次
a[1] 可以选 x, y这两个人, 那么合并 x, y, 这两个人可以在被其他的装备选一次
按照此思路合并贪心并查集即可
int f[N];
bool v[N];
ll ans;
int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); }
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) f[i] = i;
rep (i, 1, m) {
cin >> _;
if (_ == 1) cin >> a[i].x >> a[i].w, a[i].y = a[i].x;
else cin >> a[i].x >> a[i].y >> a[i].w;
}
sort(a + 1, a + 1 + m, [](node &a, node& b) { return a.w > b.w; });
rep (i, 1, m) {
if ((a[i].x = find(a[i].x)) != (a[i].y = find(a[i].y))) {
if (!v[a[i].x] && !v[a[i].y]) ans += a[i].w, f[a[i].x] = a[i].y;
else if (!v[a[i].y] || !v[a[i].x]) ans += a[i].w, v[f[a[i].x] = a[i].y] = 1;
}
else if (!v[a[i].x = find(a[i].x)]) ans += a[i].w, v[a[i].x] = 1;
}
cout << ans;
return 0;
}
G 九峰与蛇形填数
每次操作 x, y, z, 直接暴力记录 a[x~x+k-1][y] = {操作区间 [y, y + k - 1], 操作一开始的数 v, 每次迭代加数 -1 or 1, 这次操作是第几次}
对于重复在 a[i][j] 上的操作, 根据区间 和 操作的顺序去覆盖当前位置或者下一个位置即可
输出的时候每行开个map或这优先队列 记录操作按操作的优先级排序, 暴力操作输出即可 复杂度 \(O(m * m + n * n * log_2m)\)
struct node { int a = 1, b = 2005, f = 0, t = 0, v = 0; } p, c;
int n, m, _, k, cas;
node a[2005][2005];
void add(int x, int y, node& c) {
if (a[x][y].t == 0) { a[x][y] = c; return; }
if (a[x][y].b <= c.b && c.t > a[x][y].t) { a[x][y] = c; return; }
if (a[x][y].b >= c.b && c.t < a[x][y].t) return;
else if (c.t > a[x][y].t) swap(a[x][y], c);
c.v += (a[x][y].b + 1 - c.a) * c.f; c.a = a[x][y].b + 1; add(x, c.a, c);
}
int main() {
IOS; cin >> n >> m;
rep(i, 1, m) {
int x, y, z; cin >> x >> y >> z;
rep(j, 0, z - 1)
if (j & 1) add(x + j, y, c = node{ y, y + z - 1, -1, i, (j + 1) * z });
else add(x + j, y, c = node{ y, y + z - 1, 1, i, j * z + 1 });
}
rep(i, 1, n) {
int c = 0; node cur = p; map<int, node> st;
rep(j, 1, n) {
if (a[i][j].t && a[i][j].t < cur.t) { if (a[i][j].b > cur.b) st[a[i][j].t] = a[i][j]; }
else if (a[i][j].t) {
if (a[i][j].b < cur.b) st[cur.t] = cur;
cur = a[i][j]; c = a[i][j].v;
}
cout << c << ' ';
while (j >= cur.b) {
auto it = st.end(); --it;
cur = it->second; st.erase(it);
c = cur.v + (j - cur.a) * cur.f;
}
c += cur.f;
}
cout << '\n';
}
return 0;
}
H 吴楚月的表达式
又不含括号, 遍历就行
ll v[N], a[N], b[N];
vector<pair<int, char>> h[N];
ll qpow(ll a, int b) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
void dfs(int x, int f, char op) {
if (op == '+') b[x] = v[x], a[x] = (a[f] + b[x]) % mod;
else if (op == '-') b[x] = mod - v[x], a[x] = (a[f] + b[x]) % mod;
else if (op == '*') b[x] = b[f] * v[x] % mod, a[x] = (a[f] - b[f] + mod + b[x]) % mod;
else if (op == '/') b[x] = b[f] * qpow(v[x], mod - 2) % mod, a[x] = (a[f] - b[f] + mod + b[x]) % mod;
for (auto y : h[x]) dfs(y.fi, x, y.se);
}
int main() {
IOS; cin >> n;
rep(i, 1, n) cin >> v[i];
rep(i, 2, n) cin >> b[i];
rep(i, 2, n) {
char op; cin >> op;
h[b[i]].pb(i, op);
}
a[1] = b[1] = v[1]; dfs(1, 0, ' ');
rep(i, 1, n) cout << a[i] << ' ';
return 0;
}
J 邬澄瑶的公约数
质因数分解
ll qpow(ll a, int b) {
ll ans = 1;
for (; b; b >>= 1, a = a * a % mod) if (b & 1) ans = ans * a % mod;
return ans;
}
void work(int n) {
memset(b, 0, sizeof b);
for (int i = 2; i <= n / i; ++i)
while (n % i == 0) ++b[i], n /= i;
++b[n];
}
int main() {
IOS; cin >> n;
rep (i, 1, n) cin >> x[i];
rep (i ,1, n) cin >> p[i]; work(x[1]);
rep (i, 2, 1e4) a[i] = b[i] * p[1];
rep (i, 2, n) {
work(x[i]);
rep (j, 1, 10000) umin(a[j], b[j] * p[i]);
}
ll ans = 1;
rep (i, 2, 10000) ans = ans * qpow(i, a[i]) % mod;
cout << ans;
return 0;
}