2018-2019 ACM-ICPC, Asia East Continent Finals Solution

D. Deja vu of … Go Players

签。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int t, n, m;
 4 
 5 int main()
 6 {
 7     scanf("%d", &t);
 8     while (t--)
 9     {
10         scanf("%d%d", &n, &m);
11         for (int i = 1; i <= n + m; ++i) scanf("%*d");
12         puts(n <= m ? "Yes" : "No");
13     }
14     return 0;
15 }
View Code

I. Misunderstood … Missing

题意:

$有n轮游戏,每一轮有三个参数a_i, b_i, c_i$

初始攻击力为$A = 0, 成长值为D = 0$

每一轮的开头 $A = A + D$

接着三种操作选一个

  • 造成$A + a_i点伤害$
  • $D = D + b_i$
  • $A = A + c_i$

求造成的最大伤害和是多少

思路:

倒着$dp, dp[i][j][k] 表示当前处于第i轮,在后面的轮数中要进行j次攻击,时间点之和为k$

那么到当前点,我们就可以

通过$k\;来算出如果当前点选择第二种操作的贡献$

$dp[i][j][k] = max(dp[i][j][k], dp[i + 1][j][k] + c[i] * j)$

$通过j\;来算出如果当前点选择第三种操作的贡献$

$dp[i][j][k] = max(dp[i][j][k], dp[i + 1][j][k] + (k - i * j) * b[i])$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 110
 6 #define M 6010
 7 int t, n;
 8 ll dp[2][N][M], a[N], b[N], c[N];
 9 
10 int main()
11 {
12     scanf("%d", &t);
13     while (t--)
14     {
15         scanf("%d", &n);
16         for (int i = 1; i <= n; ++i) scanf("%lld%lld%lld", a + i, b + i, c + i);
17         for (int i = 0; i < 2; ++i) for (int j = 0; j <= n; ++j) for (int k = 0; k <= 5050; ++k) dp[i][j][k] = -1;
18         dp[n & 1 ^ 1][0][0] = 0;
19         for (int i = n; i >= 1; --i)
20         {
21             for (int j = 0; j <= n; ++j) for (int k = 0; k <= 5050; ++k) if (dp[i & 1 ^ 1][j][k] != -1) 
22             {
23                 dp[i & 1][j + 1][k + i] = max(dp[i & 1][j + 1][k + i], dp[i & 1 ^ 1][j][k] + a[i]);
24                 dp[i & 1][j][k] = max(dp[i & 1][j][k], dp[i & 1 ^ 1][j][k] + 1ll * j * c[i]);
25                 dp[i & 1][j][k] = max(dp[i & 1][j][k], dp[i & 1 ^ 1][j][k] + 1ll * (k - j * i) * b[i]);
26             }
27         }
28         ll res = 0;
29         for (int i = 1; i <= n; ++i) for (int j = 1; j <= 5050; ++j) res = max(res, dp[1][i][j]);
30         printf("%lld\n", res);
31     }
32     return 0;
33 }
View Code

L. Eventual … Journey

题意:

有两个阵营,阵营之间的人可以两两之间通过花费1来相互到达

不同阵营之间如果有直接边也可以直接相互到达,如果没有直接边,可以通过间接到达

即先到达一个有边连到对方阵营的同阵营的人,再过去

思路:

考虑花费一共有三种情况

1:同阵营之间的相互到达,不同阵营之间有边可以直接到达

2:不同阵营之间没有直接边,但是有一方有直接边连向对方阵营

3:两个属于不同阵营,且都没有直接边连向对方阵营

要注意m = 0的时候,不同阵营之间不可达

还有 它给出的公共边可能有相同阵营的

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 100010
 5 int n, m;
 6 int cnt[2], zero[2], degree[N], vis[N];
 7 
 8 int main()
 9 {
10     while (scanf("%d%d", &n, &m) != EOF)
11     {
12         memset(degree, 0, sizeof degree);
13         cnt[0] = cnt[1] = 0;
14         zero[0] = zero[1] = 0;
15         for (int i = 1; i <= n; ++i) 
16         {
17             scanf("%d", vis + i);
18             ++cnt[vis[i]];
19         }
20         if (m == 0)
21         {
22             for (int i = 1; i <= n; ++i) printf("%d%c", cnt[vis[i]] - 1, " \n"[i == n]);
23             continue;
24         }
25         for (int i = 1, u, v; i <= m; ++i)
26         {
27             scanf("%d%d", &u, &v);
28             if (vis[u] == vis[v]) continue;
29             ++degree[u];
30             ++degree[v];
31         }
32         for (int i = 1; i <= n; ++i) if (!degree[i])
33             ++zero[vis[i]];
34         for (int i = 1; i <= n; ++i)
35         {
36             int res = 0;
37             if (degree[i]) res = cnt[vis[i]] - 1 + degree[i] + (cnt[vis[i] ^ 1] - degree[i]) * 2;
38             else res = cnt[vis[i]] - 1 + cnt[vis[i] ^ 1] * 2 + zero[vis[i] ^ 1];
39             printf("%d%c", res, " \n"[i == n]); 
40         }
41     }
42     return 0;
43 }
View Code

猜你喜欢

转载自www.cnblogs.com/Dup4/p/10228817.html