Educational Codeforces Round 56 Solution

A. Dice Rolling

签到.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int t, n;
 5 
 6 int main()
 7 {
 8     scanf("%d", &t);
 9     while (t--)
10     {
11         scanf("%d", &n);
12         if (n <= 7) puts("1");
13         else
14         {
15             int res = 0;
16             res += n / 7;
17             printf("%d\n", res + 1);   
18         }
19     }
20     return 0;
21 }
View Code

B. Letters Rearranging

签到.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 1010
 5 int t, cnt[30];
 6 char s[N];
 7 
 8 bool ok()
 9 {
10     for (int i = 1, len = strlen(s + 1); i < len; ++i) if (s[i] != s[i + 1])
11         return false;
12     return true;
13 }
14 
15 int main()
16 {
17     scanf("%d", &t);
18     while (t--)
19     {
20         scanf("%s", s + 1);
21         if (ok()) puts("-1");
22         else
23         {
24             for (int i = 2, len = strlen(s + 1); i < len; ++i) if(s[i] != s[1])  
25                 swap(s[i], s[len]);
26             printf("%s\n", s + 1); 
27         }
28     }
29     return 0;
30 }
View Code

C. Mishka and the Last Exam

签到.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 200010
 6 int n;
 7 ll b[N], a[N];
 8 
 9 int main()
10 {
11     while (scanf("%d", &n) != EOF)
12     {
13         for (int i = 1; i <= (n >> 1); ++i) scanf("%lld", b + i);
14         a[1] = 0; a[n] = b[1];
15         ll base = 0;
16         for (int i = 2; i <= (n >> 1); ++i)
17         {
18             ll gap = b[i] - base - a[n - i + 2];
19             base += max(0ll, gap);
20             a[i] = base;
21             a[n - i + 1] = b[i] - a[i];
22         }
23         for (int i = 1; i <= n; ++i) printf("%lld%c", a[i], " \n"[i == n]);
24     }
25     return 0;
26 }
View Code

D. Beautiful Graph

Solved.

题意:

有$1, 2, 3三种权值,给每个点赋权值$

使得每条边所连的两个点的权值和为奇数,求方案数

思路:

显然,一条边所连的两点的权值分配只有两种

$(2, 1) 或者 (2, 3)$

把$2看作一类,(1, 3)看作一类,就相当于两种颜色染色$

那么判一下是否是二分图就知道有无方案数

再考虑DFS树,对于同属于一个连通块的点构成的DFS树

如果根节点确定了,那么其他结点也就确定要放哪类数字

那么枚举根节点要放的数字类别,对于$(1, 3)这类数字求一下方案数,有两种即可$

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define ll long long
  5 #define N 300010
  6 const ll MOD = 998244353;
  7 int t, n, m;
  8 vector <int> G[N];
  9 
 10 ll qmod(ll base, ll n)
 11 {
 12     ll res = 1;
 13     while (n)
 14     {
 15         if (n & 1) res = (res * base) % MOD;
 16         base = base * base % MOD;
 17         n >>= 1;
 18     }
 19     return res;
 20 }
 21 
 22 int vis[N], deep[N], fa[N], cnt[N];
 23 bool DFS(int u)
 24 {
 25     vis[u] = 1;
 26     for (auto v : G[u]) if (v != fa[u])
 27     {
 28         if (vis[v])
 29         {
 30             if ((deep[u] - deep[v]) % 2 == 0) return false;
 31             continue;
 32         }
 33         fa[v] = u;
 34         deep[v] = deep[u] + 1;
 35         if (DFS(v) == false) return false;
 36     }
 37     return true;
 38 }
 39 
 40 bool ok()
 41 {
 42     for (int i = 1; i <= n; ++i) if (!vis[i])
 43     {
 44         fa[i] = i; 
 45         deep[i] = 0;
 46         if (DFS(i) == false) return false; 
 47     }
 48     return true;
 49 }
 50 
 51 stack <int> s;
 52 ll DFS(int u, int vi)
 53 {
 54     ll res = 1;
 55     vis[u] = 1;  
 56     s.push(u);
 57     for (auto v : G[u]) if (v != fa[u] && !vis[v])
 58     {
 59         fa[v] = u;
 60         res = (res * (DFS(v, vi ^ 1)) % MOD);  
 61     } 
 62     if (vi) return res * 2 % MOD;
 63     else return res;
 64 }
 65 
 66 ll work()
 67 {
 68     for (int i = 1; i <= n; ++i) vis[i] = 0;
 69     ll res = 1;
 70     for (int i = 1; i <= n; ++i) if (!vis[i])
 71     {
 72         while (!s.empty()) s.pop();
 73         fa[i] = i;
 74         ll tmp = DFS(i, 0);
 75         while (!s.empty()) 
 76         {
 77             vis[s.top()] = 0;
 78             s.pop();
 79         }
 80         tmp = (tmp + DFS(i, 1)) % MOD;
 81         res = (res * tmp) % MOD;
 82     }
 83     return res;
 84 }
 85 
 86 int main()
 87 {
 88     scanf("%d", &t);
 89     while (t--)
 90     {
 91         scanf("%d%d", &n, &m);
 92         for (int i = 1; i <= n; ++i) G[i].clear(), vis[i] = 0, cnt[i] = 0;
 93         for (int i = 1, u, v; i <= m; ++i) 
 94         {
 95             scanf("%d%d", &u, &v);
 96             G[u].push_back(v);
 97             G[v].push_back(u); 
 98         }
 99         if (!ok()) puts("0");
100         else printf("%lld\n", work()); 
101     }
102     return 0;
103 }
View Code

E. Intersection of Permutations

Unsolved.

题意:

给出两个排列,两种操作

1° 求$[l_a, r_a]中和[l_b, r_b]中都出现的数的个数$

2° 交换$b排列中两个数的位置$

F. Vasya and Array

Upsolved.

题意:

给出一个序列,有些位置有数,有些位置没有,可以自己填$[1, k]中的数$

求没有一段长度为$len的连续的序列是同一个数的填数方案$

思路:

$dp[i][j]表示第i个位置放第j个数的方案,sum[i] = \sum_{j = 1}^{k}dp[i][j]$

再考虑转移

$如果a[i] == -1,那么枚举[1, k]每个数,转移的时候就是dp[i][j] = sum[i - 1]$

但是要减去不合法的状态

不合法的状态就是$sum[i - len] - dp[i - len][j]$

为什么要减去$dp[i - len][j],因为这是长度为len + 1 的, 在之前减去过$

对于$a[i] = 特定的数的转移也如此$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 100010
 6 const ll MOD = 998244353;
 7 int n, k, l, a[N];
 8 ll dp[N][110], sum[N], len[110];
 9 
10 int main()
11 {
12     while (scanf("%d%d%d", &n, &k, &l) != EOF)
13     {
14         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
15         memset(dp, 0, sizeof dp);
16         memset(sum, 0, sizeof sum);
17         memset(len, 0, sizeof len);
18         sum[0] = 1;
19         for (int i = 1; i <= n; ++i)
20         {
21             for (int j = 1; j <= k; ++j) len[j] = (a[i] == -1 || a[i] == j) ? len[j] + 1 : 0;
22             if (a[i] == -1)
23             {
24                 for (int j = 1; j <= k; ++j)
25                 {
26                     dp[i][j] = sum[i - 1];
27                     if (len[j] >= l)
28                         dp[i][j] = (dp[i][j] - (sum[i - l] - dp[i - l][j] + MOD) % MOD + MOD) % MOD;
29                 }
30             }
31             else
32             {
33                 dp[i][a[i]] = sum[i - 1];
34                 if (len[a[i]] >= l)
35                     dp[i][a[i]] = (dp[i][a[i]] - (sum[i - l] - dp[i - l][a[i]] + MOD) % MOD + MOD) % MOD;
36             }
37             for (int j = 1; j <= k; ++j) sum[i] = (sum[i] + dp[i][j]) % MOD;
38         }
39         printf("%lld\n", sum[n]);
40     }
41     return 0;
42 }
View Code

G. Multidimensional Queries

Upsolved.

题意:

在一个k维平面上求区间两点最远曼哈顿距离

思路:

曼哈顿距离可以通过枚举符号的正负状态来取最大值

注意到$k并不大,那么线段树维护在一种符号状态下的最大和最小值即可$

会有一些不合法的状态,但是这些不合法的状态一定会有另外一个合法的状态并且使得答案比不合法状态更优

所以不合法状态是不用管的

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 200010
 5 #define INF 0x3f3f3f3f
 6 int n, k, q, a[N][10];
 7 
 8 struct SEG
 9 {
10     struct node
11     {
12         int Max, Min;
13         node () {}
14         node (int Max, int Min) : Max(Max), Min(Min) {}
15         void init() { Max = -INF, Min = INF; }    
16         node operator + (const node &other) const { return node (max(Max, other.Max), min(Min, other.Min)); }
17     }a[N << 2], res; 
18     void build(int id, int l, int r)
19     {
20         a[id].init();
21         if (l == r) return;
22         int mid = (l + r) >> 1;
23         build(id << 1, l, mid);
24         build(id << 1 | 1, mid + 1, r);
25     }
26     void update(int id, int l, int r, int pos, int val)
27     {
28         if (l == r) 
29         {
30             a[id] = node(val, val);
31             return;
32         }
33         int mid = (l + r) >> 1;
34         if (pos <= mid) update(id << 1, l, mid, pos, val);
35         else update(id << 1 | 1, mid + 1, r, pos, val);
36         a[id] = a[id << 1] + a[id << 1 | 1];
37     }
38     void query(int id, int l, int r, int ql, int qr)
39     {
40         if (l >= ql && r <= qr)
41         {
42             res = res + a[id];
43             return;
44         }
45         int mid = (l + r) >> 1;
46         if (ql <= mid) query(id << 1, l, mid, ql, qr);
47         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
48     }
49 }seg[1 << 5];
50 
51 int main()
52 {
53     while (scanf("%d%d", &n, &k) != EOF)
54     {
55         for (int i = 1; i <= n; ++i) for (int j = 0; j < k; ++j) scanf("%d", a[i] + j);
56         for (int i = 0; i < (1 << k); ++i)
57         {
58             seg[i].build(1, 1, n);
59             for (int j = 1; j <= n; ++j)
60             {
61                 int tmp = 0;
62                 for (int o = 0; o < k; ++o) 
63                     tmp += a[j][o] * ((((i >> o) & 1) == 0) ? -1 : 1);
64                 seg[i].update(1, 1, n, j, tmp);
65             }
66         }
67         scanf("%d", &q);
68         for (int i = 1, op, x, l, r; i <= q; ++i)
69         {
70             scanf("%d", &op);
71             if (op == 1)
72             {
73                 scanf("%d", &x);
74                 for (int j = 0; j < k; ++j) scanf("%d", a[x] + j);
75                 for (int j = 0; j < (1 << k); ++j)
76                 {
77                     int tmp = 0;
78                     for (int o = 0; o < k; ++o)
79                         tmp += a[x][o] * (((j >> o) & 1) == 0 ? -1 : 1);
80                     seg[j].update(1, 1, n, x, tmp);  
81                 }
82             }
83             else
84             {
85                 scanf("%d%d", &l, &r);
86                 int res = -INF;
87                 for (int j = 0; j < (1 << k); ++j) 
88                 {
89                     seg[j].res.init();
90                     seg[j].query(1, 1, n, l, r);
91                     res = max(res, seg[j].res.Max - seg[j].res.Min);
92                 }
93                 printf("%d\n", res);
94             }
95         }
96     }
97     return 0;
98 }
View Code

猜你喜欢

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