2020国庆清北学堂Day1解题报告

A 打扑克:

显然需要将 个数奇偶与先手是谁 分成四部分讨论

容易得到 偶个数偶先手偶必胜 与 奇个数奇先手奇必胜 的结论

那么剩下两个 case 呢?

容易得到 偶个数奇先手偶必胜,毕竟奇永远比偶少1

同时可以手玩得到 奇个数偶先手偶必胜,因为偶数掌握牌权的同时奇数有一个必白给的1

注意特判两张牌的情况

 1 #include <ctime>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <iostream>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <queue>
10 #define inf 100010
11 #define INF 0x7fffffff
12 #define ll long long
13 
14 namespace chiaro{
15 
16 template <class I>
17 inline void read(I &num){
18     num = 0; char c = getchar(), up = c;
19     while(c < '0' || c > '9') up = c, c = getchar();
20     while(c >= '0' && c <= '9') num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar();
21     up == '-' ? num = -num : 0; return;
22 }
23 template <class I>
24 inline void read(I &a, I &b) {read(a); read(b);}
25 template <class I>
26 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
27 
28 inline void solve () {
29     char c = getchar(), up = c;
30     int len = 0;
31     while(!isdigit(c)) c = getchar();
32     while(isdigit(c)) ++len, up = c, c = getchar();
33     int o; read(o);
34     int n = up - '0'; o = !o;
35     if(len == 1 && n == 2) {
36         printf("%d\n", !o);
37         return;
38     }
39     int win = 0;
40     if((o & 1) && (n & 1)) win = 0;
41     else if((o & 1) == 0 && (n & 1) == 0) win = 1;
42     else win = 1;
43     printf("%d\n", win);
44 }
45 
46 inline int main(){
47     int T; read(T);
48     while(T--) solve();
49     return 0;
50 }
51 
52 }
53 
54 signed main(){ return chiaro::main();}

B. 粉刷匠

可以发现,一个位置归属于谁只取决于最后一次覆盖到他的操作,所以可以考虑到倒着进行操作

已覆盖的位置不可能再被覆盖,直接对于覆盖成 1 的操作统计答案即可

 1 #include <ctime>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <iostream>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <queue>
10 #define inf 1000010
11 #define INF 0x7fffffff
12 #define ll long long
13 
14 namespace chiaro{
15 
16 template <class I>
17 inline void read(I &num){
18     num = 0; char c = getchar(), up = c;
19     while(c < '0' || c > '9') up = c, c = getchar();
20     while(c >= '0' && c <= '9') num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar();
21     up == '-' ? num = -num : 0; return;
22 }
23 template <class I>
24 inline void read(I &a, I &b) {read(a); read(b);}
25 template <class I>
26 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
27 
28 int n[2];
29 int q;
30 int x[inf], y[inf], z[inf];
31 bool vis[2][inf];
32 
33 inline int main(){
34     read(n[0], n[1], q);
35     for(int i = 1; i <= q; i++) read(x[i], y[i], z[i]);
36     ll ans = 0;
37     for(int i = q; i; --i) {
38         if(vis[x[i]][y[i]]) continue;
39         vis[x[i]][y[i]] = 1;
40         if(z[i]) ans += n[!x[i]];
41         --n[x[i]];
42     }
43     printf("%lld\n", ans);
44     return 0;
45 }
46 
47 }
48 
49 signed main(){ return chiaro::main();}

C. 直线竞速

考虑优化暴力,容易知道关键在于怎样快速求得区间不排序第 k 大

可以使用分治,同时 algorithm 库中的 STL 函数 std::nth_element() 可以直接完成这步操作

 1 #include <ctime>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <iostream>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <queue>
10 #define inf 100010
11 #define INF 0x7fffffff
12 #define ll long long
13 
14 namespace chiaro{
15 
16 template <class I>
17 inline void read(I &num){
18     num = 0; char c = getchar(), up = c;
19     while(c < '0' || c > '9') up = c, c = getchar();
20     while(c >= '0' && c <= '9') num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar();
21     up == '-' ? num = -num : 0; return;
22 }
23 template <class I>
24 inline void read(I &a, I &b) {read(a); read(b);}
25 template <class I>
26 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
27 
28 struct Person {
29     ll dis;
30     int id;
31 };
32 
33 int n, q;
34 ll v[inf], a[inf];
35 std::pair <ll, int> x[inf];
36 
37 inline bool cmp(Person &a, Person &b) {
38     return (a.dis == b.dis) ? (a.id < b.id) : (a.dis > b.dis);
39 }
40 
41 inline void setting(){
42 #ifndef ONLINE_JUDGE
43     freopen("C.in", "r", stdin);
44     freopen("C.out", "w", stdout);
45 #endif
46     return;
47 }
48 
49 inline bool cmp (const std::pair <ll, int> &a, const std::pair <ll, int> &b) {
50     return a.first > b.first;
51 }
52 
53 inline int main(){
54     // setting();
55     read(n);
56     for(int i = 1; i <= n; i++) read(v[i], a[i]);
57     read(q);
58     while(q--) {
59         ll t, k; read(t, k);
60         for(int i = 1; i <= n; i++) x[i] = std::make_pair(a[i] + 1ll * t * v[i], -i);
61         std::nth_element(x + 1, x + k, x + 1 + n, std::greater <std::pair <ll, int> >());
62         printf("%lld\n", -x[k].second);
63     }
64     return 0;
65 }
66 
67 }
68 
69 signed main(){ return chiaro::main();}

考虑其他做法

可以发现如果将一辆车超越另一辆车称作 交换 的话,全局最多进行 $n^2$ 次的交换

那我们可以将询问按照时间为关键字排序

然后按照冒泡排序的思想来进行更新

根据上述性质,容易得到时间复杂度均摊 $O(n^2)$

 1 #include <ctime>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <iostream>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <queue>
10 #define inf 100010
11 #define INF 0x7fffffff
12 #define ll long long
13 
14 namespace chiaro{
15 
16 template <class I>
17 inline void read(I &num){
18     num = 0; char c = getchar(), up = c;
19     while(c < '0' || c > '9') up = c, c = getchar();
20     while(c >= '0' && c <= '9') num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar();
21     up == '-' ? num = -num : 0; return;
22 }
23 template <class I>
24 inline void read(I &a, I &b) {read(a); read(b);}
25 template <class I>
26 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
27 
28 struct Node {
29     ll a;
30     int b;
31     int id;
32     ll tmp;
33 };
34 
35 int n, T;
36 Node c[inf];
37 Node q[inf];
38 
39 inline bool cmpA (const Node &a, const Node &b) {return a.a > b.a;}
40 inline bool cmpB (const Node &a, const Node &b) {return a.b > b.b;}
41 inline bool cmpID (const Node &a, const Node &b) {return a.id < b.id;}
42 
43 inline void bubble(int now) {
44     for(int i = 1; i <= n; i++) {
45         for(int j = i; j > 1; --j) {
46             ll x = q[now].a * c[j].a + c[j].b;
47             ll y = q[now].a * c[j - 1].a + c[j - 1].b;
48             if(y < x) std::swap(c[j], c[j - 1]);
49             else if(x == y && c[j].id < c[j - 1].id) std::swap(c[j], c[j - 1]);
50             else break;
51         }
52     }
53     return;
54 }
55 
56 inline int main(){
57     read(n);
58     for(int i = 1; i <= n; i++) {
59         int v, a; read(v, a);
60         c[i].a = v, c[i].b = a;
61         c[i].id = i;
62     }
63     read(T);
64     for(int i = 1; i <= T; i++) {
65         int t, k; read(t, k);
66         q[i].a = t, q[i].b = k;
67         q[i].id = i;
68     }
69     std::sort(c + 1, c + 1 + n, cmpB);
70     std::sort(q + 1, q + 1 + T, cmpA);
71     for(int i = 1; i <= T; i++) {
72         bubble(i);
73         q[i].tmp = c[q[i].b].id;
74     }
75     std::sort(q + 1, q + 1 + T, cmpID);
76     for(int i = 1; i <= T; i++) printf("%lld\n", q[i].tmp);
77     return 0;
78 }
79 
80 }
81 
82 signed main(){ return chiaro::main();}

D. 游戏

容易想到 $O(n^2m^2)$ 暴力,考虑发掘更多性质

可以想到有性质,对于一次删除操作对应 A 串 a,和对应的 B 串 b,那么一定存在 a 或者 b 长度为 1 

可以考虑证明:

$$x\times y+a\times b<(x+a)\times(y+b)$$

$$Q.E.D$$

所以可以将状态更换成 $f[0/1][i][j]$ 表示 a 还是 b 串最后一个删除的串长度为 1,同时 a 串处理到了 i 位,b 串处理到了 j 位

可以分别考虑删除两个长度为 1 和不为 1 的串串,或者删除两个长度为 1 的串串

$O(1)$ 转移

 1 #include <ctime>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <iostream>
 7 #include <algorithm>
 8 #include <vector>
 9 #include <queue>
10 #define inf 2010
11 #define INF 0x7fffffff
12 #define ll long long
13 
14 namespace chiaro{
15 
16 template <class I>
17 inline void read(I &num){
18     num = 0; char c = getchar(), up = c;
19     while(c < '0' || c > '9') up = c, c = getchar();
20     while(c >= '0' && c <= '9') num = (num << 1) + (num << 3) + (c ^ '0'), c = getchar();
21     up == '-' ? num = -num : 0; return;
22 }
23 template <class I>
24 inline void read(I &a, I &b) {read(a); read(b);}
25 template <class I>
26 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
27 
28 int n, m;
29 int a[inf], b[inf];
30 ll suma[inf], sumb[inf];
31 ll dp[2][inf][inf];
32 
33 inline int main(){
34     read(n, m);
35     for(int i = 1; i <= n; i++) read(a[i]), --a[i];
36     for(int i = 1; i <= m; i++) read(b[i]), --b[i];
37     memset(dp, 0x3f, sizeof(dp));
38     dp[0][0][0] = dp[1][0][0] = 0;
39     for(int i = 1; i <= n; i++) {
40         for(int j = 1; j <= m; j++) {
41             ll trans = 1ll * a[i] * b[j];
42             dp[0][i][j] = std::min (dp[0][i][j - 1], std::min (dp[0][i - 1][j - 1], dp[1][i - 1][j - 1])) + trans;
43             dp[1][i][j] = std::min (dp[1][i - 1][j], std::min (dp[0][i - 1][j - 1], dp[1][i - 1][j - 1])) + trans;
44         }
45     }
46     printf("%lld\n", std::min (dp[0][n][m], dp[1][n][m]));
47     return 0;
48 }
49 
50 }
51 
52 signed main(){ return chiaro::main();}

 

posted @ 2020-10-01 20:45  Chiaro  阅读(162)  评论(0)    收藏  举报