codeforces Round 593(div. 2)


A、Stones

题意:

给出三种石头分别$a$,$b$,$c$个,每次拿石头的时候只能拿$1$个第一种石头和$2$个第二种石头,或者$1$个第二种石头和$2$个第三种石头,求最多能拿到多少?

题解:

先考虑后一种方案:这样子一共拿了$min(b, c/2)*3$个石头,然后剩下的石头再取$min((b-c/2)/2,a)*3$.

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     int n;
 6     scanf("%d", &n);
 7     while (n--)
 8     {
 9         int a, b, c;
10         scanf("%d%d%d", &a, &b, &c);
11         int ans = 0;
12         while (b > 0 && c > 1)
13         {
14             ans += 3;
15             b -= 1;
16             c -= 2;
17         }
18         while (b > 1 && a > 0)
19         {
20             ans += 3;
21             b -= 2;
22             a -= 1;
23         }
24         printf("%d\n", ans);
25     }
26     return 0;
27 }
View Code

B、Alice and the List of Presents

题意:

给出无限个$n$种东西放进$m$个包且每个包中不出现重复元素的方案数,包里面可以不放东西。

题解:

考虑每个包里面都可以放或者不放某东西,一共$2^m-1$种,然后一共有$n$个物品,所以就是$(2^m-1)^n$种。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll mod = 1e9 + 7;
 5 ll pow(ll a, ll b, ll p)
 6 {
 7     ll res = 1;
 8     while (b)
 9     {
10         if (b & 1)
11             res = res * a % p;
12         a = a * a % p;
13         b >>= 1;
14     }
15     return res;
16 }
17 int main()
18 {
19     ll n, m;
20     scanf("%lld%lld", &n, &m);
21     printf("%lld", pow((pow(2, m, mod) - 1ll + mod) % mod, n, mod));
22     return 0;
23 }
View Code

C、Labs

题意:

定义$f(X,Y)$是$X$集合中$a$,和$Y$集合中的$b$满足$a>b$的数对的数量。给出一个$n\times n$的矩阵,元素是$1~n^2$,求出一种填数方式,使得对于所有的行,最大的$f(X_i,X_j)$最小。

题解:

考虑要最大的最小,首先发现因为所有的数都不一样,所以$f(X,Y)+f(Y,X)=n*n$,则我们需要找到一种分法,使得所有的行之间的$max(f(X,Y),f(Y,X))$等于$\frac {n*n}{2}$。所以,我们可以把这$n*n$个数按顺序分成$n$组,然后就第一组选$max$,第二组选$min$,第三组选$max$交替选够$n$个数,构成第一行,然后第二行从$min$选起,交替选够$n$个数,以此类推,观察矩阵的数可以发现规律,按规律写出代码即可。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 3e2 + 5;
 4 int ans[N][N];
 5 int main()
 6 {
 7     int n;
 8     scanf("%d", &n);
 9     for (int i = 1; i <= n; ++i)
10         for (int j = 1; j <= n; ++j)
11             ans[i][j] = i + n * (j - 1);
12     for (int i = 2; i <= n; i += 2)
13         for (int j = 1; j <= n / 2; ++j)
14             swap(ans[j][i], ans[n - j + 1][i]);
15     for (int i = 1; i <= n; ++i)
16         for (int j = 1; j <= n; ++j)
17             printf("%d%c", ans[i][j], " \n"[j == n]);
18     return 0;
19 }
View Code

D、Alice and the Doll

题意:

给出一个玩偶,它只能向前和向右,这个玩偶在$(1,1)$开始,走一个有障碍物的$n*m$的方格图,求能不能走完所有不是障碍物的格子。

题解:

理论上直接模拟就行,但是这样子时间复杂度是$O(n*m)$,所以我们预处理出每一行每一列所有障碍物,排好序,这样子就可以用二分查找找出前面的第一个障碍物。这样子时间就降到$O(nlogn)$了。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1e5 + 5;
 4 typedef long long ll;
 5 vector<int> G1[N];
 6 vector<int> G2[N];
 7 int main()
 8 {
 9     int n, m, k;
10     scanf("%d%d%d", &n, &m, &k);
11     for (int i = 1; i <= k; ++i)
12     {
13         int a, b;
14         scanf("%d%d", &a, &b);
15         G1[a].push_back(b);
16         G2[b].push_back(a);
17     }
18     for (int i = 1; i <= n; ++i)
19         sort(G1[i].begin(), G1[i].end());
20     for (int i = 1; i <= m; ++i)
21         sort(G2[i].begin(), G2[i].end());
22     bool f = 0;
23     ll ans = 1;
24     int x = 1, y = 1;
25     int up = 1, down = n, left = 1, right = m;
26     int dir = 0;
27     while (1)
28     {
29         int ny, nx;
30         if (dir == 0) //右方向
31         {
32             int pos = lower_bound(G1[x].begin(), G1[x].end(), y) - G1[x].begin();
33             nx = x;
34             if (pos == G1[x].size())
35                 ny = right;
36             else
37                 ny = min(right, G1[x][pos] - 1);
38             up = x + 1;
39         }
40         else if (dir == 1) //下方向
41         {
42             int pos = lower_bound(G2[y].begin(), G2[y].end(), x) - G2[y].begin();
43             ny = y;
44             if (pos == G2[y].size())
45                 nx = down;
46             else
47                 nx = min(down, G2[y][pos] - 1);
48             right = y - 1;
49         }
50         else if (dir == 2)
51         {
52             int pos = lower_bound(G1[x].begin(), G1[x].end(), y) - G1[x].begin() - 1;
53             nx = x;
54             if (pos < 0)
55                 ny = left;
56             else
57                 ny = max(left, G1[x][pos] + 1);
58             down = x - 1;
59         }
60         else if (dir == 3)
61         {
62             int pos = lower_bound(G2[y].begin(), G2[y].end(), x) - G2[y].begin() - 1;
63             ny = y;
64             if (pos < 0)
65                 nx = up;
66             else
67                 nx = max(up, G2[y][pos] + 1);
68             left = y + 1;
69         }
70         if (nx == x && ny == y && f)
71             break;
72         dir = (dir + 1) % 4;
73         ans += abs(nx - x) + abs(ny - y);
74         x = nx;
75         y = ny;
76         f = 1;
77     }
78     if (ans == (ll)n * m - k)
79         printf("Yes\n");
80     else
81         printf("No\n");
82     return 0;
83 }
View Code

E、Alice and the Unfair Game

题意:

给出$n$的盒子,其中有一个盒子有宝物,$A$会给出一个位置$pos$,如果猜对了就赢了,为了防止赢,在$A$猜了之后,宝物可以向相邻的盒子转移,设开始时宝物在$x$,猜$m$次之后在$y$,求$(x,y)$的数量。

题解:

这样的问题通pos_i常建图解决,实际上就是求从起点开始走了$m$步之后到达的位置的集合。但是这里因为它只能向相邻盒子走,所以我们直接扩展出$(m+2)\times n$的矩阵,$(i,pos_i)$表示障碍,找到从$(0,x)$走到$(m+1,y)$的路径数就是答案,显然,找出从一个点贪心向左走或者贪心向右走的区间后,区间内的所有位置都可达。然后可以得到$l_{a_i+i}=l_{a_i+i+1}+1$,$r_i$同理,因为考虑到可能存在$i$和$j$使得$i+a_i=j+a_j$,则需要倒序枚举。然后再对每一个点$(0,x)$求出在第$m+1$行的范围,累加即可。

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1e5 + 5;
 4 typedef long long ll;
 5 int a[N], l[N << 2], r[N << 2];
 6 const int offset = 1e5;
 7 int main()
 8 {
 9     int n, m;
10     scanf("%d%d", &n, &m);
11     for (int i = 1; i <= m; ++i)
12         scanf("%d", &a[i]);
13     if (n == 1)
14         return printf("0\n"), 0;
15     for (int i = m; i >= 1; --i)
16     {
17         l[a[i] - i + offset] = l[a[i] - i - 1 + offset] + 1;
18         r[a[i] + i + offset] = r[a[i] + i + 1 + offset] + 1;
19     }
20     ll ans = 0;
21     for (int i = 1; i <= n; ++i)
22     {
23         int rr = min(n, i + m + 1 - l[i + offset]);
24         int ll = max(1, i - m - 1 + r[i + offset]);
25         ans += rr - ll + 1;
26     }
27     printf("%lld\n", ans);
28     return 0;
29 }
View Code
posted @ 2020-07-08 12:27  Aya_Uchida  阅读(151)  评论(0编辑  收藏  举报