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 intView Coderes = 0; 16 res += n / 7; 17 printf("%d\n", res + 1); 18 } 19 } 20 return 0; 21 }
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 8View Codebool 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 else23 { 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 }
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