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 ", 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 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 ", 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], " "[i == n]); 24 } 25 return 0; 26 }
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 ", work()); 101 } 102 return 0; 103 }
E. Intersection of Permutations
Unsolved.
题意:
给出两个排列,两种操作
1° 求$[l_a, r_a]中和[l_b, r_b]中都出现的数的个数$
2° 交换$b排列中两个数的位置$
思路:
CDQ分治:
先$CDQ(l, mid), 再处理当前的(l, r) 在处理(mid + 1, r)$
$但是要注意 处理完(mid + 1, r)后要将换动的位置换回去$
$但是处理了(l, r)之后不要将换动还原,先处理(mid + 1, r),因为这部分的换动是基于(l, r)的$

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 int n, m, q, a[N], b[N], posa[N], posb[N]; 6 int qid; 7 struct qnode 8 { 9 int op, pos, l, r, x, y, id; 10 qnode() {} 11 qnode(int op, int pos, int x, int y) : op(op), pos(pos), x(x), y(y) {} 12 bool operator < (const qnode &other) const 13 { 14 if (pos != other.pos) 15 return pos < other.pos; 16 return op < other.op; 17 } 18 }arr[N << 4], tarr[N << 4]; 19 int ans[N]; 20 21 namespace BIT 22 { 23 int a[N]; 24 void init() { memset(a, 0, sizeof a); } 25 void update(int x, int val) 26 { 27 for (; x < N; x += x & -x) 28 a[x] += val; 29 } 30 int query(int x) 31 { 32 int res = 0; 33 for (; x > 0; x -= x & -x) 34 res += a[x]; 35 return res; 36 } 37 int query(int l, int r) 38 { 39 if (r < l) return 0; 40 return query(r) - query(l - 1); 41 } 42 }; 43 44 void CDQ(int l, int r) 45 { 46 if (r <= l) return; 47 int mid = (l + r) >> 1; 48 CDQ(l, mid); 49 int w = 0; 50 for (int i = l; i <= mid; ++i) 51 { 52 if (arr[i].op != 1) 53 { 54 if (arr[i].op == 0) 55 tarr[++w] = arr[i]; 56 else 57 { 58 int x = arr[i].x, y = arr[i].y; 59 int A = posa[b[x]]; 60 int B = posa[b[y]]; 61 tarr[++w] = qnode(0, A, x, -1); 62 tarr[++w] = qnode(0, A, y, 1); 63 tarr[++w] = qnode(0, B, y, -1); 64 tarr[++w] = qnode(0, B, x, 1); 65 swap(b[x], b[y]); 66 } 67 } 68 } 69 for (int i = mid + 1; i <= r; ++i) 70 { 71 if (arr[i].op == 1) 72 tarr[++w] = arr[i]; 73 } 74 sort(tarr + 1, tarr + 1 + w); 75 for (int i = 1; i <= w; ++i) 76 { 77 if (tarr[i].op == 0) 78 BIT::update(tarr[i].x, tarr[i].y); 79 else 80 ans[tarr[i].id] += BIT::query(tarr[i].l, tarr[i].r) * tarr[i].y; 81 } 82 for (int i = 1; i <= w; ++i) if (tarr[i].op == 0) 83 BIT::update(tarr[i].x, -tarr[i].y); 84 //printf("%d %d %d ", l, mid, r); 85 //for (int i = 1; i <= qid; ++i) printf("%d%c", ans[i], " "[i == qid]); 86 CDQ(mid + 1, r); 87 for (int i = mid; i >= l; --i) if (arr[i].op == 2) swap(b[arr[i].x], b[arr[i].y]); 88 } 89 90 int main() 91 { 92 while (scanf("%d%d", &n, &m) != EOF) 93 { 94 memset(ans, 0, sizeof ans); BIT::init(); 95 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 96 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 97 for (int i = 1; i <= n; ++i) posa[a[i]] = i; 98 for (int i = 1; i <= n; ++i) posb[b[i]] = i; 99 int op, la, ra, lb, rb, x, y; q = 0; qid = 0; 100 for (int i = 1; i <= n; ++i) 101 arr[++q] = qnode(0, i, posb[a[i]], 1); 102 for (int i = 1; i <= m; ++i) 103 { 104 scanf("%d", &op); 105 if (op == 1) 106 { 107 ++qid; 108 scanf("%d%d%d%d", &la, &ra, &lb, &rb); 109 arr[++q].op = 1; 110 arr[q].pos = la - 1; 111 arr[q].l = lb; 112 arr[q].r = rb; 113 arr[q].id = qid; 114 arr[q].y = -1; 115 arr[++q].op = 1; 116 arr[q].pos = ra; 117 arr[q].l = lb; 118 arr[q].r = rb; 119 arr[q].id = qid; 120 arr[q].y = 1; 121 } 122 else 123 { 124 scanf("%d%d", &x, &y); 125 arr[++q].op = 2; 126 arr[q].x = x; 127 arr[q].y = y; 128 } 129 } 130 CDQ(1, q); 131 for (int i = 1; i <= qid; ++i) printf("%d ", ans[i]); 132 } 133 return 0; 134 }
分块极限卡过:
对$b[]分块,整块二分查找,角块暴力$
查询复杂度$O(frac{n}{S} cdot log(S))$
修改复杂度$O(S cdot log(S))$
让这两个复杂度尽量相等即可
时间复杂度$O(nsqrt{n}log(sqrt{n}))$

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 #define unit 400 6 #define S 1010 7 int n, m, a[N], b[N]; 8 9 int pos[N], posl[S], posr[S]; 10 vector <int> v[S]; 11 12 bool in(int x, int a, int b) 13 { 14 if (x >= a && x <= b) return true; 15 return false; 16 } 17 18 int query(int l, int r, int x, int y) 19 { 20 int res = 0; 21 if (pos[l] == pos[r]) 22 { 23 for (int i = l; i <= r; ++i) if (in(a[b[i]], x, y)) 24 ++res; 25 } 26 else 27 { 28 for (int i = l; i <= posr[pos[l]]; ++i) if (in(a[b[i]], x, y)) 29 ++res; 30 for (int i = posl[pos[r]]; i <= r; ++i) if (in(a[b[i]], x, y)) 31 ++res; 32 for (int i = pos[l] + 1; i <= pos[r] - 1; ++i) 33 res += upper_bound(v[i].begin(), v[i].end(), y) - lower_bound(v[i].begin(), v[i].end(), x); 34 } 35 return res; 36 } 37 38 void update(int x) 39 { 40 v[x].clear(); 41 for (int i = posl[x]; i <= posr[x]; ++i) v[x].push_back(a[b[i]]); 42 sort(v[x].begin(), v[x].end()); 43 } 44 45 int main() 46 { 47 while (scanf("%d%d", &n, &m) != EOF) 48 { 49 for (int i = 1; i <= n; ++i) pos[i] = (i - 1) / unit + 1; 50 for (int i = 1; i <= n; ++i) 51 { 52 posr[pos[i]] = i; 53 if (i == 1 || pos[i] != pos[i - 1]) 54 posl[pos[i]] = i; 55 } 56 for (int i = 1; i <= pos[n]; ++i) v[i].clear(); 57 for (int i = 1, x; i <= n; ++i) 58 { 59 scanf("%d", &x); 60 a[x] = i; 61 } 62 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 63 for (int i = 1; i <= n; ++i) 64 v[pos[i]].push_back(a[b[i]]); 65 for (int i = 1; i <= pos[n]; ++i) sort(v[i].begin(), v[i].end()); 66 int op, l[2], r[2], x, y; 67 for (int i = 1; i <= m; ++i) 68 { 69 scanf("%d", &op); 70 if (op == 1) 71 { 72 for (int i = 0; i < 2; ++i) scanf("%d%d", l + i, r + i); 73 printf("%d ", query(l[1], r[1], l[0], r[0])); 74 } 75 else 76 { 77 scanf("%d%d", &x, &y); 78 swap(b[x], b[y]); 79 update(pos[x]); 80 if (pos[x] != pos[y]) update(pos[y]); 81 } 82 } 83 } 84 return 0; 85 }
分块:
对$a[], b[]分别分块$
$维护一个sum[i][j]表示b的第i块对a的前j块的贡献$
$整块的贡献一起处理,角块暴力$
$修改的时候只有两个整块会有变化,暴力重构$
时间复杂度$O(nsqrt{n})$

1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 #define unit 250 6 #define M 1010 7 int n, m; 8 int a[N], b[N], A[N], B[N]; 9 int pos[N], posl[M], posr[M]; 10 int sum[M][M], f[M][M]; 11 12 int main() 13 { 14 while (scanf("%d%d", &n, &m) != EOF) 15 { 16 for (int i = 1; i <= n; ++i) pos[i] = (i - 1) / unit + 1; 17 for (int i = 1; i <= n; ++i) 18 { 19 if (i == 1 || pos[i] != pos[i - 1]) posl[pos[i]] = i; 20 posr[pos[i]] = i; 21 } 22 for (int i = 1; i <= n; ++i) scanf("%d", a + i), A[a[i]] = i; 23 for (int i = 1; i <= n; ++i) scanf("%d", b + i), B[b[i]] = i; 24 for (int i = 1; i <= n; ++i) 25 ++f[pos[i]][pos[A[b[i]]]]; 26 for (int i = 1; i <= pos[n]; ++i) 27 for (int j = 2; j <= pos[n]; ++j) 28 sum[i][j] += sum[i][j - 1] + f[i][j]; 29 int op, la, ra, lb, rb, x, y; 30 while (m--) 31 { 32 scanf("%d", &op); 33 if (op == 1) 34 { 35 int res = 0; 36 scanf("%d%d%d%d", &la, &ra, &lb, &rb); 37 if (pos[la] == pos[ra]) 38 { 39 for (int i = la; i <= ra; ++i) 40 res += (B[a[i]] >= lb && B[a[i]] <= rb); 41 } 42 else if (pos[lb] == pos[rb]) 43 { 44 for (int i = lb; i <= rb; ++i) 45 res += (A[b[i]] >= la && A[b[i]] <= ra); 46 } 47 else 48 { 49 for (int i = pos[lb] + 1; i < pos[rb]; ++i) 50 res += sum[i][pos[ra] - 1] - sum[i][pos[la]]; 51 for (int i = la; i <= posr[pos[la]]; ++i) 52 res += (B[a[i]] >= lb && B[a[i]] <= rb); 53 for (int i = posl[pos[ra]]; i <= ra; ++i) 54 res += (B[a[i]] >= lb && B[a[i]] <= rb); 55 for (int i = lb; i <= posr[pos[lb]]; ++i) 56 res += (A[b[i]] >= posl[pos[la] + 1] && A[b[i]] <= posr[pos[ra] - 1]); 57 for (int i = posl[pos[rb]]; i <= rb; ++i) 58 res += (A[b[i]] >= posl[pos[la] + 1] && A[b[i]] <= posr[pos[ra] - 1]); 59 } 60 printf("%d ", res); 61 } 62 else 63 { 64 int id; 65 scanf("%d%d", &x, &y); 66 id = A[b[x]]; 67 --f[pos[x]][pos[id]]; 68 id = A[b[y]]; 69 --f[pos[y]][pos[id]]; 70 swap(B[b[x]], B[b[y]]); 71 swap(b[x], b[y]); 72 id = A[b[x]]; 73 ++f[pos[x]][pos[id]]; 74 id = A[b[y]]; 75 ++f[pos[y]][pos[id]]; 76 for (int i = 1; i <= pos[n]; ++i) sum[pos[x]][i] = sum[pos[x]][i - 1] + f[pos[x]][i]; 77 for (int i = 1; i <= pos[n]; ++i) sum[pos[y]][i] = sum[pos[y]][i - 1] + f[pos[y]][i]; 78 } 79 } 80 } 81 return 0; 82 }
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 ", sum[n]); 40 } 41 return 0; 42 }
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 ", res); 94 } 95 } 96 } 97 return 0; 98 }