1. 程式人生 > >Educational Codeforces Round 56 Solution

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