20200515 河北工业大学ACM校队五月选拔赛 题解
Posted hebut-amadeus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20200515 河北工业大学ACM校队五月选拔赛 题解相关的知识,希望对你有一定的参考价值。
作为本场被请来(抓来)验题的人,我也是见证了这次比赛赛前裁判组的准备,尤其是icpc的系统,真的很不容易,在此为大家点个赞
验题的代码我就放到我的博客上了
A
输出Hl即可
#include<bits/stdc++.h> #define LL long long #define maxn 100010 using namespace std; int main(){ printf("Hl "); return 0; }
B
推公式题
对于连续抽i张卡,对答案的贡献为n^i
易推出
当m=1时答案是n
否则答案是m的n次方-1再除以m-1
#include<bits/stdc++.h> #define LL long long #define maxn 100010 using namespace std; LL qpow(LL n, LL c){ LL base = n, ret = 1; while(c){ if(c & 1){ ret = ret * base; } base = base * base; c = c >> 1; } return ret; } int main(){ LL m, n; while(~scanf("%lld %lld", &n, &m)){ if(m == 1){ printf("%lld ", n); } else{ printf("%lld ", (qpow(m, n) - 1) / (m - 1)); } } }
C
用dfs搜索即可,注意边界条件
#include<bits/stdc++.h> #define LL long long #define maxn 110 using namespace std; char a[maxn][maxn]; bool vis[maxn][maxn]; int n, m; void _dfs(int x, int y){ if(x < 0 || x >= n || y < 0 || y >= m){ return; } if(a[x][y] != ‘@‘){ return; } if(vis[x][y]){ return; } vis[x][y] = 1; _dfs(x + 1, y); _dfs(x - 1, y); _dfs(x, y + 1); _dfs(x, y - 1); _dfs(x + 1, y - 1); _dfs(x + 1, y + 1); _dfs(x - 1, y - 1); _dfs(x - 1, y + 1); return; } int main(){ cin >> n >> m; for(int i = 0; i < n; ++i){ for(int j = 0; j < m; ++j){ cin >> a[i][j]; } } int ans = 0; memset(vis, 0, sizeof vis); for(int i = 0; i < n; ++i){ for(int j = 0; j < m; ++j){ if(a[i][j] == ‘@‘ && !vis[i][j]){ ans = ans + 1; _dfs(i, j); } } } cout << ans << endl; return 0; }
D
最短路问题,数据很水,有n^3的算法卡过去了
#include<bits/stdc++.h> #define LL long long #define maxn 1000010 using namespace std; struct Edge{ int t; LL c; Edge(){} Edge(int _t, LL _c){ t = _t; c = _c; } bool operator < (Edge e) const{ return c > e.c; } }; LL dis[maxn]; priority_queue<Edge> p; vector<Edge> ed[maxn]; bool vis[maxn]; int main(){ int n, m; scanf("%d %d", &n, &m); int f, t, c; for(int i = 0; i < m; ++i){ scanf("%d %d %d", &f, &t, &c); ed[f].push_back(Edge(t, c)); } int S, T; scanf("%d %d", &S, &T); p.push(Edge(S, 0)); for(int i = 1; i <= n; ++i){ dis[i] = -1; vis[i] = 0; } while(!p.empty()){ Edge now = p.top(); p.pop(); if(vis[now.t]){ continue; } vis[now.t] = 1; dis[now.t] = now.c; for(int i = 0; i < ed[now.t].size(); ++i){ p.push(Edge(ed[now.t][i].t, ed[now.t][i].c + now.c)); } } printf("%lld ", dis[T]); return 0; }
E
本场hard难度的题之一,其实也就是俩板子拼一下
先用tarjan缩点,然后在新图里跑dijkstra(其实spfa也没卡)
#include<bits/stdc++.h> #define LL long long #define maxn 1000010 using namespace std; struct Node{ int t, c; Node(int _t = 0, int _c = 0){ t = _t; c = _c; } bool operator < (Node n) const{ return c > n.c; } }; vector<Node> ed1[maxn], ed2[maxn]; int sd[maxn], dis[maxn], dfn[maxn], low[maxn], cnt, th; bool vis[maxn]; stack<int> s; void tarjan(int u) { dfn[u] = low[u] = ++cnt; vis[u] = 1; s.push(u); for(int i = 0; i < ed1[u].size(); ++i){ int v = ed1[u][i].t; if(!dfn[v]){ tarjan(v); low[u] = min(low[u],low[v]); } else if(vis[v]){ low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]){ th++; while(1){ int v = s.top(); s.pop(); vis[v] = 0; sd[v] = th; if(u == v) break; } } } priority_queue<Node> p; int main(){ int n, m; scanf("%d %d", &n, &m); int f, t, c; for(int i = 0; i < m; ++i){ scanf("%d %d %d", &f, &t, &c); if(f == t){ continue; } ed1[f].push_back(Node(t, c)); } memset(vis, 0, sizeof vis); cnt = 0, th = 0; for(int i = 1; i <= n; i++){ if(!dfn[i]){ tarjan(i); } } for(int i = 1; i <= n; ++i){ for(int j = 0; j < ed1[i].size(); ++j){ ed2[sd[i]].push_back(Node(sd[ed1[i][j].t], ed1[i][j].c)); } } int S, T; scanf("%d %d", &S, &T); p.push(Node(sd[S], 0)); for(int i = 1; i <= n; ++i){ dis[i] = -1; vis[i] = 0; } while(!p.empty()){ Node now = p.top(); p.pop(); if(vis[now.t]){ continue; } vis[now.t] = 1; dis[now.t] = now.c; for(int i = 0; i < ed2[now.t].size(); ++i){ p.push(Node(ed2[now.t][i].t, ed2[now.t][i].c + now.c)); } } printf("%d ", dis[sd[T]]); return 0; }
F
我们遍历2到n-1,对每个n能取模为0的数,判断是否为质数,然后按格式输出就行了
#include<bits/stdc++.h> #define LL long long #define maxn 100010 using namespace std; bool isPrime(int n){ for(int i = 2; i <= sqrt(n); ++i){ if(n % i == 0){ return false; } } return true; } string IntToString(int n){ string ret = ""; while(n){ ret.push_back(char((n % 10) + ‘0‘)); n = n / 10; } reverse(ret.begin(), ret.end()); return ret; } vector<int> v; int main(){ int n; scanf("%d", &n); for(int i = 2; i <= n; ++i){ if(n % i == 0 && isPrime(i)){ v.push_back(i); } } string ans = ""; ans = ans + IntToString(n); for(int i = 0; i < v.size(); ++i){ ans = ans + "*(1-1/" + IntToString(v[i]) + ")"; } cout << ans << endl; return 0; }
G
就找个最大值就行了
#include<bits/stdc++.h> #define LL long long #define maxn 100010 using namespace std; int main(){ int n; cin >> n; int t, ma = -100; for(int i = 0; i < n * n; ++i){ cin >> t; ma = max(t, ma); } cout << ma << endl; return 0; }
H
我们先打质数表,然后算前缀和
对i,如果i是质数,那么pre[i] = pre[i - 1] + 1;
否则pre[i] = pre[i - 1];
然后对每组l跟r,前缀和做差就行了
#include<bits/stdc++.h> #define LL long long #define maxn 1000010 using namespace std; bool isp[maxn]; int prep[maxn]; int main(){ for(int i = 2; i < maxn; ++i){ if(!isp[i]){ for(int j = i + i; j < maxn; j = j + i){ isp[j] = 1; } } prep[i] = prep[i - 1] + (isp[i] ^ 1); } int q; scanf("%d", &q); int l, r; while(q--){ scanf("%d %d", &l, &r); if(l == 0){ printf("%d ", prep[r]); } else{ printf("%d ", prep[r] - prep[l - 1]); } } return 0; }
I
拿来防AK的,我们先推dp式子,容斥算出六种置换中不动点分别有多少
然后使用牛顿迭代推F(x^2),F(x^3),套FFT即可
具体可以看这一篇:https://baka.online/%E7%83%B7%E5%9F%BA%E8%AE%A1%E6%95%B0-burnside%E5%BC%95%E7%90%86%E7%94%9F%E6%88%90%E5%87%BD%E6%95%B0fft/
#include <bits/stdc++.h> typedef long long ll; const int N = 8e5 + 233, P = 998244353; inline ll fpow(ll x, int y) { ll ret = 1; for ( ; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P; return ret; } const int Gp = 3, Gpi = fpow(Gp, P - 2); int rev[N], L, lim; inline void init(int n) { L = 0, lim = 1; while (lim < n) lim <<= 1, ++L; for (int i = 1; i < lim; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1)); } inline void NTT(ll f[], int o) { for (int i = 1; i < lim; ++i) if (i < rev[i]) std::swap(f[i], f[rev[i]]); for (int i = 1; i < lim; i <<= 1) { ll T = fpow(o == 1 ? Gp : Gpi, (P - 1) / (i << 1)); for (int j = 0; j < lim; j += i << 1) { ll w = 1; for (int k = 0; k < i; ++k, w = w * T % P) { ll nx = f[j + k], ny = f[i + j + k] * w % P; f[j + k] = nx + ny >= P ? nx + ny - P : nx + ny; f[i + j + k] = nx - ny >= 0 ? nx - ny : nx - ny + P; } } } if (o == -1) { ll inv = fpow(lim, P - 2); for (int i = 0; i < lim; ++i) f[i] = f[i] * inv % P; } } void get_inv(ll F[], ll G[], int n) { if (n == 1) { G[0] = fpow(F[0], P - 2); return; } get_inv(F, G, (n + 1) >> 1); static ll T[N]; init(n << 1); for (int i = 0; i < lim; ++i) T[i] = i < n ? F[i] : 0; NTT(G, 1), NTT(T, 1); for (int i = 0; i < lim; ++i) G[i] = ((2 - G[i] * T[i]) % P + P) * G[i] % P; NTT(G, -1); for (int i = n; i < lim; ++i) G[i] = 0; } int n; ll A[N], B[N], C[N], D[N], E[N], F[N]; void solve(int n) { if (n == 1) return A[0] = 1, void(); solve((n + 1) >> 1); init(n << 1); for (int i = 0; i < lim; ++i) B[i] = C[i] = D[i] = E[i] = F[i] = 0; for (int i = 0; i < n; ++i) { if (i * 2 < n) B[i * 2] = A[i]; if (i * 3 < n) C[i * 3] = A[i]; } NTT(A, 1), NTT(B, 1), NTT(C, 1); for (int i = 0; i < lim; ++i) { D[i] = (A[i] * A[i] % P * A[i] % P + 3 * B[i] * A[i] % P + 2 * C[i]) % P; E[i] = (3 * A[i] * A[i] % P + 3 * B[i]) % P; } NTT(A, -1), NTT(D, -1), NTT(E, -1); for (int i = lim - 1; i; --i) D[i] = D[i - 1], E[i] = E[i - 1]; D[0] = 6; E[0] = P - 6; for (int i = 0; i < lim; ++i) D[i] = (D[i] - 6 * A[i] % P + P) % P; get_inv(E, F, lim); NTT(D, 1), NTT(F, 1); for (int i = 0; i < lim; ++i) F[i] = (P - D[i] * F[i] % P) % P; NTT(F, -1); for (int i = 0; i < lim; ++i) A[i] = (A[i] + F[i]) % P; for (int i = n; i < lim; ++i) A[i] = 0; } int main() { std::cin >> n; init(n); solve(n + 1); std::cout << A[n] << std::endl; return 0; }
希望大家玩的开心!
以上是关于20200515 河北工业大学ACM校队五月选拔赛 题解的主要内容,如果未能解决你的问题,请参考以下文章