福州大学第十三届程序设计竞赛_重现

8/9

Problem A Calculus Midterm

题意:略

题解:~~

 

Problem B 翻翻棋

题意:略

题解:~~

 

Problem C 平行四边形数

题意:略

题解:~~

 

Problem D 炉石传说

题意:略

题解:最直接的一个做法就是二分图,跑一遍判断是否匹配的数量为n。还可以的一个做法是贪心:先把对手的血量从大到小排,然后对于自己,选一个能满足对方攻击的自身攻击力最小的一个随从,然后不断重复,最后判断有无可选即可。

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 using namespace std;
 6 
 7 #define lson l, m, rt << 1
 8 #define rson m + 1, r, rt << 1 | 1
 9 #define ll long long
10 #define xx first
11 #define yy second
12 
13 const int maxn = 110;
14 int n, from[maxn], used[maxn];
15 int G[maxn][maxn], a[maxn], b[maxn], c[maxn], d[maxn];
16 
17 bool is_match(int u) {
18   for (int v = 0; v < n; v++) if (G[u][v] && !used[v]) {
19     used[v] = 1;
20     if (from[v] == -1 || is_match(from[v])) {
21       from[v] = u;
22       return true;
23     }
24   }
25   return false;
26 }
27 
28 int max_match() {
29   int ret = 0;
30   memset(from, -1, sizeof from);
31   for (int i = 0; i < n; i++) {
32     memset(used, 0, sizeof used);
33     ret += is_match(i);
34   }
35   return ret;
36 }
37 
38 int main() {
39 //  freopen("case.in", "r", stdin);
40   int T;
41   cin >> T;
42   while (T--) {
43     scanf("%d", &n);
44     for (int i = 0; i < n; i++) scanf("%d%d", a + i, b + i);
45     for (int i = 0; i < n; i++) scanf("%d%d", c + i, d + i);
46     memset(G, 0, sizeof G);
47     for (int i = 0; i < n; i++)
48       for (int j = 0; j < n; j++) {
49         if (a[i] - d[j] > 0 && c[j] - b[i] <= 0) G[i][j] = 1;
50       }
51     if (max_match() == n) puts("Yes"); else puts("No");
52   }
53   return 0;
54 }
代码君(二分图)

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <vector>
 4 #include <cstring>
 5 #include <queue>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 #define lson l, m, rt << 1
10 #define rson m + 1, r, rt << 1 | 1
11 #define xx first
12 #define yy second
13 
14 typedef pair<int,int> pii;
15 typedef long long ll;
16 const int maxn = 110, inf = 1 << 20;
17 int n;
18 
19 struct Node {
20   int x, y, isdeath;
21   Node(int x=0, int y=0, int isdeath=0) : x(x), y(y), isdeath(isdeath) {}
22   bool operator < (const Node& o) const {
23     return x > o.x;
24   }
25 };
26 
27 Node a[maxn], b[maxn];
28 
29 bool check() {
30   for (int i = 0; i < n; i++) {
31     int best = inf, bestid;
32     for (int j = 0; j < n; j++) if (!a[j].isdeath) {
33       if (a[j].x - b[i].y > 0 && b[i].x - a[j].y <= 0) {
34         if (best > a[j].x) best = a[bestid = j].x;
35       }
36     }
37     if (best == inf) return false;
38     a[bestid].isdeath = 1;
39   }
40   return true;
41 }
42 
43 int main() {
44 //  freopen("case.in", "r", stdin);
45   int T;
46   scanf("%d", &T);
47   while (T--) {
48     scanf("%d", &n);
49     for (int i = 0; i < n; i++) scanf("%d%d", &a[i].x, &a[i].y);
50     for (int i = 0; i < n; i++) scanf("%d%d", &b[i].x, &b[i].y);
51     for (int i = 0; i < n; i++) a[i].isdeath = b[i].isdeath = 0;
52     sort(b, b + n);
53     check() ? puts("Yes") : puts("No");
54   }
55   return 0;
56 }
代码君(贪心)

 

Problem E ~APTX4869

题意:略

题解:对于这种最小值最大化的问题,用二分答案来处理。先二分出一个答案,然后对于每一对点如果小于这个答案那么一定要放在同一个集合,所以就连一条边代表这两个点一定是同一集合,然后最后dfs一个点,把能够标记的点都标记,最后看有没有剩下点,有的话就说明这个方案是合法的,否则不合法,然后不断往下分。

 

 1 /*zhen hao*/
 2 #include <vector>
 3 #include <cstring>
 4 #include <cstdio>
 5 using namespace std;
 6 
 7 #define lson l, m, rt << 1
 8 #define rson m + 1, r, rt << 1 | 1
 9 #define ll long long
10 #define xx first
11 #define yy second
12 
13 const int maxn = 8e2 + 10;
14 int v[maxn][maxn], id[maxn], n;
15 vector<int> G[maxn];
16 
17 void dfs(int u) {
18   id[u] = 1;
19   for (int i = 0; i < (int)G[u].size(); i++) {
20     int v = G[u][i];
21     if (id[v] == -1) dfs(v);
22   }
23 }
24 
25 bool check(int M) {
26   for (int i = 0; i < n; i++) { G[i].clear(); id[i] = -1; }
27   for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) if (i != j && v[i][j] < M)
28     G[i].push_back(j);
29   dfs(0);
30   for (int i = 0; i < n; i++) if (id[i] == -1) return 1;
31   return 0;
32 }
33 
34 int main() {
35 //  freopen("case.in", "r", stdin);
36   while (scanf("%d", &n) == 1) {
37     int L = 0, R = 0;
38     for (int i = 0; i < n; i++)
39       for (int j = 0; j < n; j++) {
40         scanf("%d", &v[i][j]);
41         R = max(R, v[i][j]);
42       }
43 
44     while (L <= R) {
45       int M = (L + R) / 2;
46       if (check(M)) L = M + 1;
47       else R = M - 1;
48     }
49     printf("%d
", R);
50   }
51 }
代码君

 

Problem F 牧场物语

题意:略

题解:dp[i][j][k]表示走了i步,然后第一次走停留在j行,第二次走停留在k行,为什么要这样呢?首先他要求的是最短路,所以一定是dp(否则可以用网络流)。然后就是当步数和行数确定的时候对应的列也是确定的。状态转移就四种,下下,下右,右下,右右。

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 #define lson l, m, rt << 1
 7 #define rson m + 1, r, rt << 1 | 1
 8 #define ll long long
 9 #define xx first
10 #define yy second
11 
12 const int maxn = 110;
13 const ll inf = 1LL << 60;
14 ll dp[maxn << 1][maxn][maxn], v[maxn][maxn];
15 
16 void init(int n) {
17   for (int i = 0; i < 2 * n; i++)
18     for (int j = 0; j < n; j++)
19       for (int k = 0; k < n; k++)
20         dp[i][j][k] = -inf;
21 }
22 
23 int main() {
24 //  freopen("case.in", "r", stdin);
25   int n;
26   while (scanf("%d", &n) == 1) {
27     for (int i = 0; i < n; i++)
28       for (int j = 0; j < n; j++)
29         scanf("%I64d", &v[i][j]);
30 
31     init(n);
32     dp[0][0][0] = v[0][0];
33 
34     for (int i = 0; i < 2 * n - 2; i++)
35       for (int j = 0; j < n; j++)
36         for (int k = 0; k < n; k++) if (dp[i][j][k] != -inf) {
37           int jj = i - j, kk = i - k;
38 //          cout << j << ' ' << jj << ' ' << k << ' ' << kk << endl;
39           if (j != n - 1 && k != n - 1) {
40             if (j != k) dp[i + 1][j + 1][k + 1] = max(dp[i + 1][j + 1][k + 1], dp[i][j][k] + v[j + 1][jj] + v[k + 1][kk]);
41             else dp[i + 1][j + 1][k + 1] = max(dp[i + 1][j + 1][k + 1], dp[i][j][k] + v[j + 1][jj]);
42           }
43           if (j != n - 1 && kk != n - 1) {
44             if (j + 1 != k) dp[i + 1][j + 1][k] = max(dp[i + 1][j + 1][k], dp[i][j][k] + v[j + 1][jj] + v[k][kk + 1]);
45             else dp[i + 1][j + 1][k] = max(dp[i + 1][j + 1][k], dp[i][j][k] + v[j + 1][jj]);
46           }
47           if (jj != n - 1 && k != n - 1) {
48             if (j != k + 1) dp[i + 1][j][k + 1] = max(dp[i + 1][j][k + 1], dp[i][j][k] + v[j][jj + 1] + v[k + 1][kk]);
49             else dp[i + 1][j][k + 1] = max(dp[i + 1][j][k + 1], dp[i][j][k] + v[j][jj + 1]);
50           }
51           if (jj != n - 1 && kk != n - 1) {
52             if (j != k) dp[i + 1][j][k] = max(dp[i + 1][j][k], dp[i][j][k] + v[j][jj + 1] + v[k][kk + 1]);
53             else dp[i + 1][j][k] = max(dp[i + 1][j][k], dp[i][j][k] + v[j][jj + 1]);
54           }
55         }
56     printf("%I64d
", dp[2 * n - 2][n - 1][n - 1]);
57   }
58   return 0;
59 }
代码君

 

Problem G 国王的出游

题意:略

题解:这道题咋一眼看好像要离散化模拟什么的,实际上所有的线状区域长度不超过10 ^ 5就说明可以直接进行bfs,对于找点可以放在一个数组然后二分查找一下有没有这个点即可。

 

 1 /*zhen hao*/
 2 #include <cstdio>
 3 #include <vector>
 4 #include <cstring>
 5 #include <queue>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 #define lson l, m, rt << 1
10 #define rson m + 1, r, rt << 1 | 1
11 #define ll long long
12 #define xx first
13 #define yy second
14 
15 typedef pair<int,int> pii;
16 const int maxn = 1e5 + 10;
17 int sx, sy, ex, ey, cnt;
18 pii p[maxn];
19 bool vis[maxn];
20 
21 struct Node {
22   int x, y, d;
23   Node(int x=0,int y=0, int d=0) : x(x), y(y), d(d) {}
24 };
25 
26 int bfs() {
27   queue<Node> q;
28   q.push(Node(sx, sy, 0));
29   memset(vis, false, sizeof vis);
30   pii tp = make_pair(sx, sy);
31   int k = lower_bound(p, p + cnt, tp) - p;
32   vis[k] = 1;
33   while (!q.empty()) {
34     Node u = q.front(); q.pop();
35     if (u.x == ex && u.y == ey) return u.d;
36     for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) if (i != 0 || j != 0) {
37       int nx = u.x + i, ny = u.y + j;
38       tp = make_pair(nx, ny);
39       k = lower_bound(p, p + cnt, tp) - p;
40       if (p[k] != tp || vis[k]) continue;
41       vis[k] = 1;
42       q.push(Node(nx, ny, u.d + 1));
43     }
44   }
45   return -1;
46 }
47 
48 int main() {
49 //  freopen("case.in", "r", stdin);
50   while (scanf("%d%d%d%d", &sx, &sy, &ex, &ey) == 4) {
51     int x;
52     scanf("%d", &x);
53     cnt = 0;
54     for (int i = 0; i < x; i++) {
55       int r, a, b;
56       scanf("%d%d%d", &r, &a, &b);
57       for (int j = a; j <= b; j++)
58         p[cnt++] = make_pair(r, j);
59     }
60     p[cnt++] = make_pair(sx, sy);
61     p[cnt++] = make_pair(ex, ey);
62     sort(p, p + cnt);
63 
64     printf("%d
", bfs());
65 
66   }
67   return 0;
68 }
代码君

 

Problem H 第十四个目标

题意:略

题解:dp+离散化用二分即可。

 

Problem I 中位数

题意:略

题解:据说是主席树,然而并不会,先留个坑。

原文地址:https://www.cnblogs.com/zhenhao1/p/5459618.html