A. 题目描述: 数据范围:
题解: 代码: 题目描述: $ n $ 把武器,每把拥有伤害 $ a_i $ 和冷却时间 $ d_i $ ,父亲随机选择一把,小明选择一把,求小明赢的最大概率
数据范围:略
题解: 计算每把武器获得胜利所需要的时间 $ (ceil(100/a_i) - 1) \times d_i $ 注意需要减一。然后排序,与最小的时间相同的概率都是 $ 0.5 / n $ ,其他的则为 $ 1 / n $
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <bits/stdc++.h> #define ll long long using namespace std ;const ll mod = 1e9 + 7 ;const int inf = 0x3f3f3f3f ;const double eqs = 1e-5 ;const int maxn = 1e3 + 10 ;int t, n, m, k;int a[maxn];int main () {#ifndef ONLINE_JUDGE freopen("in.txt" , "r" , stdin ); #endif scanf ("%d" , &t); int x, y; while (t--) { scanf ("%d" , &n); for (int i = 1 ; i <= n; i++) { scanf ("%d%d" , &x, &y); a[i] = (ceil (100.0 / x) - 1 ) * y; } sort(a + 1 , a + 1 + n); int tot = 0 , tmp = a[1 ]; for (int i = 1 ; i <= n; i++) { if (a[i] == tmp) { tot++; } } printf ("%.10f\n" , 0.5 / n * tot + 1.0 / n * (n - tot)); } return 0 ; }
题目描述:
数据范围: $ 1\le T \le 30 $
$ 1\le n, m \le 1000 $
$ 1\le w_i \le 1000, -10^9 \le v_i \le 10^9 $
题解: 对第二个班级的 $ w_i $ 取反,可以使用 $ 0-1 $ 背包,使用一维空间即可。
如果直接按照输入 $ dp $ 的话, $ w $ 一直为正累加会有 $ 1e6 $ ,值域太大了,可以用用 $ random\_shuffle $ 随机化一下位置,这样大概可以保证前面的 $ w $ 和在 $ 0 $ 附近上下浮动了。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <bits/stdc++.h> using namespace std ;typedef long long ll;mt19937 rnd (time(NULL )) ;const ll INF = 1e18 ;const int N = 2005 , M = 200005 , bas = M / 2 ;struct node { int ty, w, v; } a[N<<1 ];int n, m, lim, L, R;ll F[M], G[M]; void cmax (ll &x, ll y) { if (y > x) x = y; } ll solve () { cin >> n >> m; for (int i = 1 ; i <= n + m; i ++) { cin >> a[i].w >> a[i].v; a[i].ty = (i <= n ? 1 : -1 ); } shuffle(a + 1 , a + n + m + 1 , rnd); lim = sqrt (n + m) * 1000 * 2 ; ll *f = F + bas, *g = G + bas; f[L = R = 0 ] = 0 ; for (int i = 1 ; i <= n + m; i ++) { if (a[i].ty == 1 ) { int nR = min(R + a[i].w, lim); for (int j = L; j <= R; j ++) { g[j] = f[j]; } for (int j = R + 1 ; j <= nR; j ++) { g[j] = -INF; } for (int j = L; j <= nR - a[i].w; j ++) { cmax(g[j + a[i].w], f[j] + a[i].v); } R = nR; } else { int nL = max(L - a[i].w, -lim); for (int j = L; j <= R; j ++) { g[j] = f[j]; } for (int j = nL; j <= L - 1 ; j ++) { g[j] = -INF; } for (int j = nL + a[i].w; j <= R; j ++) { cmax(g[j - a[i].w], f[j] + a[i].v); } L = nL; } swap(f, g); } return f[0 ]; } int main () { int Test; cin >> Test; for (int Case = 1 ; Case <= Test; Case ++) { printf ("%lld\n" , solve()); } return 0 ; }
题目描述: $ n $ 个点 $ m $ 条双向边。有三种状态 $ LRM $ ,每个点拥有一种状态,张三从 $ s $ 到 $ t $ , $ L $ 状态需要使用左手, $ R $ 使用右手, $ M $ 无限制。左右手转换需要花费 $ x $ 。问最小花费。
数据范围: $ 1\le T \le 100 $
$ 1\le n \le 10^5, 1\le m \le 2\times10^5, 1\le x \le 10^9 $
$ 1\le w \le 10^9 $
题解: 图上的决策问题,分层图最短路,虚拟结点。
分层图最短路可以使用 $ dp $ 方式,开二维数组,也可以分点,将点分成不同的状态。
将点只看做 $ LR $ 两个状态,开辟两倍的空间。每个点有三种状态,组合一下九种状态,使用循环建边比较方便。最后判断一下起点终点类型,跑一下最短路。也可以建几个虚拟结点让起点的两个状态,终点的两个状态都连过去,直接跑最短路。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 #include <bits/stdc++.h> #define ll long long using namespace std ;const ll mod = 1e9 + 7 ;const ll INF_LL = 0x3f3f3f3f3f3f3f3f ;const int INF = 0x3f3f3f3f ;const double eqs = 1e-5 ;const int maxn = 2e5 + 10 ;const int maxm = 5e5 + 10 ;const char TYPE[3 ] = "LR" ;int tcase, n, m, k;int s, t, x;char type[maxn];int head[maxn], cnt;struct Edge { int v, next; ll w; } edge[maxm << 1 ]; inline void addEdge (int u, int v, ll w) { ++cnt; edge[cnt] = {v, head[u], w}; head[u] = cnt; } bool vis[maxn];ll dis[maxn]; void dijstra (int s) { priority_queue<pair<ll, int >> q; memset (dis, 0x3f , sizeof (dis)); memset (vis, false , sizeof (vis)); dis[s] = 0 ; q.push({-dis[s], s}); while (!q.empty()) { auto out = q.top(); q.pop(); int u = out.second; if (vis[u]) continue ; vis[u] = true ; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].v; if (dis[u] + edge[i].w < dis[v]) { dis[v] = dis[u] + edge[i].w; q.push({-dis[v], v}); } } } } void init () { memset (head, 0 , sizeof (head)); cnt = 0 ; } int main () {#ifndef ONLINE_JUDGE #ifdef COMP_DATA freopen("/mnt/f/文档/课件/ACM比赛/2020hdu多校/第四场/data/D.in" , "r" , stdin ); freopen("out.txt" , "w" , stdout ); #else freopen("in.txt" , "r" , stdin ); #endif #endif scanf ("%d" , &tcase); while (tcase--) { scanf ("%d%d%d%d%d" , &n, &m, &s, &t, &x); init(); scanf ("%s" , type + 1 ); int u, v; ll w; for (int i = 1 ; i <= m; i++) { scanf ("%d%d%lld" , &u, &v, &w); for (int j = 0 ; j <= 1 ; j++) { for (int k = 0 ; k <= 1 ; k++) { if ((TYPE[j] == type[u] || type[u] == 'M' ) && (TYPE[k] == type[v] || type[v] == 'M' )) { addEdge(u + j * n, v + k * n, w + x * (j ^ k)); addEdge(v + k * n, u + j * n, w + x * (j ^ k)); } } } } ll ans = INF_LL; for (int i = 0 ; i <= 1 ; i++) { for (int j = 0 ; j <= 1 ; j++) { if ((TYPE[i] == type[s] || type[s] == 'M' ) && (TYPE[j] == type[t] || type[t] == 'M' )) { dijstra(s + n * i); ans = min(ans, dis[t + n * j]); } } } printf ("%lld\n" , ans); } return 0 ; }
题目描述: 定义句子相等为:对一个单词来说第 $ i $ 次出现位置相差不超过 $ 1 $
给出一个句子,问有多少种与之相等的(包括自己)
数据范围: $ 1\le T \le 100 $
$ 1\le n \le 10^5 $
$ 10 $ 个单词是最大
题解: 显然需要进行 $ DP $ 。定义 $ dp[i] $ 表示前 $ i $ 个单词有多少种句子。每一个单词只和它前面的一个相交换
a b c d e
1 2 3 4 5
假设 $ i= 5 $ ,如果 $ 5 $ 和 $ 4 $ 不交换的话 $ dp[5] = dp[4] $ ,如果交换的话 $ dp[5] = dp[3] $ ,故 $ dp[5] = dp[4] + dp[3] $ 。这是能交换的情况,如果 $ 5 == 4 $ 则不能交换 $ dp[5] = dp[4] $ ,斐波那契数列
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <bits/stdc++.h> #define ll long long using namespace std ;const ll mod = 1e9 + 7 ;const int inf = 0x3f3f3f3f ;const double eqs = 1e-5 ;const int maxn = 1e5 + 10 ;int t, n, m, k;string s[maxn];int dp[maxn];int main () {#ifndef ONLINE_JUDGE #ifdef COMP_DATA freopen("/mnt/f/文档/课件/ACM比赛/2020hdu多校/第四场/data/E.in" , "r" , stdin ); freopen("out.txt" , "w" , stdout ); #else freopen("in.txt" , "r" , stdin ); #endif #endif scanf ("%d" , &t); while (t--) { scanf ("%d" , &n); for (int i = 1 ; i <= n; i++) { cin >> s[i]; dp[i] = 0 ; } dp[0 ] = 1 ; dp[1 ] = 1 ; for (int i = 2 ; i <= n; i++) { if (s[i] != s[i-1 ]) { dp[i] = (dp[i-2 ] + dp[i-1 ] ) % mod; } else { dp[i] = dp[i - 1 ]; } } printf ("%d\n" , dp[n]); } return 0 ; }
F. 题目描述: 数据范围:
题解: 代码: 题目描述: 二维坐标系上有一些点,使用最少的斜率为 $ -1,1 $ 的直线覆盖这些点
数据范围: $ 1\le T \le 100 $
$ 1\le n \le 10^5,\sum n \le 5\times10^5 $
$ 1\le t_i, x_i \le 10^9 $
题解: 问题变成了在一个平面上找最少的直线将全部的点覆盖,将每对点的两个截距看做点,之间连一条边,看做二分图的最小顶点覆盖,求最大匹配即可。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 #include <bits/stdc++.h> #define ll long long using namespace std ;const ll mod = 1e9 + 7 ;const int INF = 0x3f3f3f3f ;const ll INF_LL = 0x3f3f3f3f3f3f3f3f ;const double eqs = 1e-5 ;const int maxn = 1e5 + 10 ;const int maxm = 1e6 + 10 ;int t, n, m, k;struct Edge { int v, next; } edge[maxm << 1 ]; int head[maxn], cnt;inline void addEdge (int u, int v) { edge[++cnt].v = v; edge[cnt].next = head[u]; head[u] = cnt; } int dx[maxn], dy[maxn]; int mx[maxn], my[maxn]; int dis;bool vis[maxn];int nx, ny;bool bfs () { queue <int > q; memset (dx, -1 , sizeof (dx)); memset (dy, -1 , sizeof (dy)); for (int i = 1 ; i <= nx; i++) { if (mx[i] == -1 ) { q.push(i); dx[i] = 0 ; } } dis = INF; while (!q.empty()) { int u = q.front(); q.pop(); if (dx[u] > dis) break ; for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].v; if (dy[v] != -1 ) continue ; dy[v] = dx[u] + 1 ; if (my[v] == -1 ) dis = dy[v]; else { dx[my[v]] = dy[v] + 1 ; q.push(my[v]); } } } return dis != INF; } bool dfs (int u) { for (int i = head[u]; i; i = edge[i].next) { int v = edge[i].v; if (!vis[v] && dy[v] == dx[u]+1 ) { vis[v] = true ; if (my[v] != -1 && dy[v] == dis) continue ; if (my[v] == -1 || dfs(my[v])) { my[v] = u; mx[u] = v; return true ; } } } return false ; } int HK () { int ans = 0 ; memset (mx, -1 , sizeof (mx)); memset (my, -1 , sizeof (my)); while (bfs()) { for (int i = 1 ; i <= ny; i++) vis[i] = false ; for (int i = 1 ; i <= nx; i++) { if (mx[i] == -1 && dfs(i)) { ans++; } } } return ans; } int a[maxn], b[maxn];int d[maxn << 1 ], top = 0 ;void init () { memset (head, 0 , sizeof (head)); cnt = 0 ; top = 0 ; } int main () {#define COMP_DATA #ifndef ONLINE_JUDGE #ifdef COMP_DATA freopen("/mnt/f/文档/课件/ACM比赛/2020hdu多校/第四场/data/G.in" , "r" , stdin ); freopen("out.txt" , "w" , stdout ); #else freopen("in.txt" , "r" , stdin ); #endif #endif scanf ("%d" , &t); while (t--) { scanf ("%d" , &n); init(); for (int i = 1 ; i <= n; i++) { scanf ("%d%d" , &a[i], &b[i]); d[++top] = a[i] + b[i]; d[++top] = a[i] - b[i]; } sort(d + 1 , d + 1 + top); nx = ny = unique(d + 1 , d + 1 + top) - d - 1 ; for (int i = 1 ; i <= n; i++) { int u = lower_bound(d + 1 , d + 1 + nx, a[i] + b[i]) - d; int v = lower_bound(d + 1 , d + 1 + nx, a[i] - b[i]) - d; addEdge(u, v); } printf ("%d\n" , HK()); } return 0 ; }
H. 题目描述: 数据范围:
题解: 代码: I. 题目描述: 数据范围:
题解: 代码: J. 题目描述: 数据范围:
题解: 代码: 题目描述: 这神仙题,两点只在万有引力作用下相向运动,求时间 $ t $ 的时候相距的距离。
数据范围: $ 1\le T \le 100 $
$ 1\le a,b,d,t\le 100 $
$ eps \le 10^{-6} $
题解: 我沙雕了,一直在推公式,结果微分方程解不出来,最后看看数据范围和样例才发现之间的力可以忽略不计,真就忽略不计了呗。直接读入输出。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <bits/stdc++.h> #define ll long long using namespace std ;const ll mod = 1e9 + 7 ;const int inf = 0x3f3f3f3f ;const double eqs = 1e-5 ;int t, n, m, k;int main () {#ifndef ONLINE_JUDGE freopen("in.txt" , "r" , stdin ); #endif scanf ("%d" , &t); while (t--) { int a, b, l, t; scanf ("%d%d%d%d" , &a, &b, &l, &t); printf ("%d\n" , l); } return 0 ; }