应该是目前为止最简单的一场。没来得及做的题待补。
题目链接:https://ac.nowcoder.com/acm/contest/884#question
A:
注意虚树直径即可。
B:
最近多校特别多线性基的题目。这题是线段树维护线性基的交。

1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou double 6 #define pb emplace_back 7 #define mp make_pair 8 #define sot(a,b) sort(a+1,a+1+b) 9 #define rep1(i,a,b) for(int i=a;i<=b;++i) 10 #define rep0(i,a,b) for(int i=a;i<b;++i) 11 #define eps 1e-8 12 #define int_inf 0x3f3f3f3f 13 #define ll_inf 0x7f7f7f7f7f7f7f7f 14 #define lson (curpos<<1) 15 #define rson (curpos<<1|1) 16 /* namespace */ 17 using namespace std; 18 /* header end */ 19 20 const int maxn = 1e5 + 10; 21 struct LinerBase { 22 int cnt; 23 ll b[32]; 24 void init() { 25 cnt = 0; 26 memset(b, 0, sizeof(b)); 27 } 28 int insert(ll x) { 29 for (int i = 31; i >= 0; i--) 30 if (x & (1ll << i)) { 31 if (b[i]) x ^= b[i]; 32 else { 33 b[i] = x; 34 cnt++; 35 return 1; 36 } 37 } 38 return 0; 39 } 40 bool check(ll x) { 41 for (int i = 31; i >= 0; i--) 42 if (x & (1ll << i)) x ^= b[i]; 43 return x == 0; 44 } 45 }; 46 47 LinerBase merge(LinerBase &a, LinerBase &b) { 48 LinerBase c, d, all; 49 for (int i = 31; i >= 0; i--) { 50 c.b[i] = 0; 51 all.b[i] = a.b[i]; 52 d.b[i] = 1ll << i; 53 } 54 for (int i = 31; i >= 0; i--) 55 if (b.b[i]) { 56 ll v = b.b[i], k = 0; int jud = 1; 57 for (int j = 31; j >= 0; j--) 58 if ((1ll << j) & v) 59 if (all.b[j]) { 60 v ^= all.b[j]; 61 k ^= d.b[j]; 62 } else { 63 jud = 0; 64 all.b[j] = v; 65 d.b[j] = k; 66 break; 67 } 68 if (jud) { 69 ll cur = 0; 70 for (int j = 31; j >= 0; j--) 71 if (k & (1ll << j)) cur ^= a.b[j]; 72 c.insert(cur); 73 } 74 } 75 return c; 76 } 77 LinerBase segt[maxn << 2], a[maxn]; 78 79 void maintain(int curpos) { 80 segt[curpos] = merge(segt[lson], segt[rson]); 81 } 82 83 void build(int curpos, int curl, int curr) { 84 if (curl == curr) { 85 segt[curpos] = a[curl]; 86 return; 87 } 88 int mid = curl + curr >> 1; 89 build(lson, curl, mid); build(rson, mid + 1, curr); 90 maintain(curpos); 91 } 92 93 bool query(int curpos, ll x, int curl, int curr, int ql, int qr) { 94 if (ql <= curl && curr <= qr) 95 return segt[curpos].check(x); 96 int mid = curl + curr >> 1; 97 if (qr <= mid) return query(lson, x, curl, mid, ql, qr); 98 if (ql > mid) return query(rson, x, mid + 1, curr, ql, qr); 99 return query(lson, x, curl, mid, ql, qr) && query(rson, x, mid + 1, curr, ql, qr); 100 } 101 102 int n, m; 103 104 int main() { 105 scanf("%d%d", &n, &m); 106 rep1(i, 1, n) { 107 int _size; scanf("%d", &_size); 108 rep1(j, 1, _size) { 109 ll x; scanf("%lld", &x); 110 a[i].insert(x); 111 } 112 } 113 build(1, 1, n); 114 while (m--) { 115 int l, r; ll x; scanf("%d%d%lld", &l, &r, &x); 116 if (query(1, x, 1, n, l, r)) puts("YES"); 117 else puts("NO"); 118 } 119 return 0; 120 }
C:
这题是2018年南昌网络赛原题(几乎,用同样做法可过),题目链接:https://nanti.jisuanke.com/t/38228
枚举区间的复杂度已经是O(n^2),完全无法接受。但不同区间的最小值情况最多只有n种。而且对于一个最小值a[i],一定存在l,r使得a[i]*sum(bl..r)最大。
那么对于任意一个a[i],假设其为最小值,往左往右扩展确定最大的区间位置;然后分两种情况:
- 若a[i]>=0,那么显然要使得sum[r]-sum[l-1]最大。因为不知道具体会确定哪个区间,那么可以把最终的区间[l,r]分为[l,i]和[i,r]两个一端确定的区间,就变成查询max(b[i]-b[l])+max(b[r]-b[i])。由于线段树只能返回值而不能返回在b数组中的位置,所以可以建立两个数组分别记录b数组的前缀后缀和,然后在这两个数组上建线段树即可。
- 若a[i]<0,把上面的max改成min,同样做法。

1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou double 6 #define pb emplace_back 7 #define mp make_pair 8 #define sot(a,b) sort(a+1,a+1+b) 9 #define rep1(i,a,b) for(int i=a;i<=b;++i) 10 #define rep0(i,a,b) for(int i=a;i<b;++i) 11 #define eps 1e-8 12 #define int_inf 0x3f3f3f3f 13 #define ll_inf 0x7f7f7f7f7f7f7f7f 14 #define lson (curpos<<1) 15 #define rson (curpos<<1|1) 16 /* namespace */ 17 using namespace std; 18 /* header end */ 19 20 const int maxn = 3e6 + 10; 21 ll a[maxn], b[maxn], s1[maxn], s2[maxn], ans = -1e18; 22 int n, l[maxn], r[maxn]; 23 24 struct SegT { 25 struct Node { 26 ll maxx, minn; 27 } node[maxn << 2]; 28 29 void build(ll *s, int curpos, int curl, int curr) { 30 if (curl == curr) { 31 node[curpos].maxx = node[curpos].minn = s[curl]; 32 return; 33 } 34 int mid = curl + curr >> 1; 35 build(s, lson, curl, mid); build(s, rson, mid + 1, curr); 36 node[curpos].maxx = max(node[lson].maxx, node[rson].maxx); 37 node[curpos].minn = min(node[lson].minn, node[rson].minn); 38 } 39 40 ll queryMax(int curpos, int curl, int curr, int ql, int qr) { 41 if (ql <= curl && curr <= qr) return node[curpos].maxx; 42 int mid = curl + curr >> 1; 43 if (qr <= mid) return queryMax(lson, curl, mid, ql, qr); 44 if (ql > mid) return queryMax(rson, mid + 1, curr, ql, qr); 45 return max(queryMax(lson, curl, mid, ql, mid), queryMax(rson, mid + 1, curr, mid + 1, qr)); 46 } 47 48 ll queryMin(int curpos, int curl, int curr, int ql, int qr) { 49 if (ql <= curl && curr <= qr) return node[curpos].minn; 50 int mid = curl + curr >> 1; 51 if (qr <= mid) return queryMin(lson, curl, mid, ql, qr); 52 if (ql > mid) return queryMin(rson, mid + 1, curr, ql, qr); 53 return min(queryMin(lson, curl, mid, ql, mid), queryMin(rson, mid + 1, curr, mid + 1, qr)); 54 } 55 } segt1, segt2; 56 57 void determinLR() { 58 stack<int>st; st.push(1); 59 l[1] = 1; r[n] = n; 60 rep1(i, 2, n) { 61 while (!st.empty() && a[i] <= a[st.top()]) st.pop(); 62 if (st.empty()) l[i] = 1; else l[i] = st.top() + 1; 63 st.push(i); 64 } 65 while (!st.empty()) st.pop(); 66 st.push(n); 67 for (int i = n - 1; i >= 1; i--) { 68 while (!st.empty() && a[i] <= a[st.top()]) st.pop(); 69 if (st.empty()) r[i] = n; else r[i] = st.top() - 1; 70 st.push(i); 71 } 72 } 73 74 int main() { 75 scanf("%d", &n); 76 s1[0] = s2[n + 1] = 0; 77 rep1(i, 1, n) scanf("%lld", &a[i]); 78 rep1(i, 1, n) { 79 scanf("%lld", &b[i]); 80 s1[i] = s1[i - 1] + b[i]; 81 } 82 for (int i = n; i >= 1; i--) s2[i] = s2[i + 1] + b[i]; 83 segt1.build(s1, 1, 1, n); segt2.build(s2, 1, 1, n); 84 determinLR(); 85 rep1(i, 1, n) { 86 ll lsum = segt2.queryMax(1, 1, n, l[i], i) - s2[i + 1], rsum = segt1.queryMax(1, 1, n, i, r[i]) - s1[i - 1]; 87 ll tmp = a[i] * (lsum + rsum - b[i]); 88 ans = max(tmp, ans); 89 lsum = segt2.queryMin(1, 1, n, l[i], i) - s2[i + 1], rsum = segt1.queryMin(1, 1, n, i, r[i]) - s1[i - 1]; 90 tmp = a[i] * (lsum + rsum - b[i]); 91 ans = max(ans, tmp); 92 } 93 printf("%lld ", ans); 94 return 0; 95 }
D:
当时打了个表看了几分钟,突然有种感觉:对于有解的不能被3整除的数n,一定只用两个数就能或出来吗?
答案是显然的。分类讨论n%3的结果即可。

1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou double 6 #define pb emplace_back 7 #define mp make_pair 8 #define sot(a,b) sort(a+1,a+1+b) 9 #define rep1(i,a,b) for(int i=a;i<=b;++i) 10 #define rep0(i,a,b) for(int i=a;i<b;++i) 11 #define eps 1e-8 12 #define int_inf 0x3f3f3f3f 13 #define ll_inf 0x7f7f7f7f7f7f7f7f 14 #define lson (curpos<<1) 15 #define rson (curpos<<1|1) 16 /* namespace */ 17 using namespace std; 18 /* header end */ 19 20 const int maxn = 1e2 + 10; 21 int func[maxn]; 22 23 int main() { 24 int t; scanf("%d", &t); 25 while (t--) { 26 ll n; scanf("%lld", &n); 27 if (n % 3 == 0) { 28 printf("1 %lld ", n); 29 continue; 30 } 31 ll cmp = n; 32 int cnt = 0; 33 while (cmp) { 34 func[++cnt] = cmp & 1; 35 cmp >>= 1; 36 } 37 rep0(i, 2, cnt) { 38 ll ans1 = 0, ans2 = 0; 39 for (int j = cnt; j >= i + 1; j--) ans1 = ans1 * 2 + func[j]; 40 for (int j = i; j >= 1; j--) ans2 = ans2 * 2 + func[j]; 41 rep1(j, 1, i) ans1 *= 2; 42 if (ans2 % 3 == 1) { 43 rep1(j, i + 1, cnt) 44 if (j % 2 == 0 && func[j]) { 45 ans2 |= (1ll << j - 1); 46 break; 47 } 48 int flag = 0; 49 if (ans2 % 3 != 0) 50 rep1(j, i + 1, cnt) 51 if (j % 2 == 1 && func[j]) { 52 if (!flag)flag = j; 53 else { 54 ans2 |= (1ll << flag - 1); ans2 |= (1ll << j - 1); 55 break; 56 } 57 } 58 } else if (ans2 % 3 == 2) { 59 rep1(j, i + 1, cnt) 60 if (j % 2 == 1 && func[j]) { 61 ans2 |= (1ll << j - 1); 62 break; 63 } 64 int flag = 0; 65 if (ans2 % 3 != 0) 66 rep1(j, i + 1, cnt) 67 if (j % 2 == 0 && func[j]) { 68 if (!flag)flag = j; 69 else { 70 ans2 |= (1ll << flag - 1); ans2 |= (1ll << j - 1); 71 break; 72 } 73 } 74 } 75 if (ans2 % 3 != 0)continue; 76 if (ans1 % 3 == 1) { 77 rep1(j, 1, i) 78 if (j % 2 == 0 && func[j]) { 79 ans1 |= (1ll << j - 1); 80 break; 81 } 82 int flag = 0; 83 if (ans2 % 3 != 0) 84 rep1(j, 1, i) 85 if (j % 2 == 1 && func[j]) { 86 if (!flag) flag = j; 87 else { 88 ans1 |= (1ll << flag - 1); ans1 |= (1ll << j - 1); 89 break; 90 } 91 } 92 } else if (ans1 % 3 == 2) { 93 rep1(j, 1, i) 94 if (j % 2 == 1 && func[j]) { 95 ans1 |= (1ll << j - 1); 96 break; 97 } 98 int flag = 0; 99 if (ans1 % 3 != 0) 100 rep1(j, 1, i) 101 if (j % 2 == 0 && func[j]) { 102 if (!flag) flag = j; 103 else { 104 ans1 |= (1ll << flag - 1); ans1 |= (1ll << j - 1); 105 break; 106 } 107 } 108 } 109 if (ans1 % 3 != 0)continue; if ((ans1 | ans2) != n)continue; 110 printf("2 %lld %lld ", ans1, ans2); 111 break; 112 } 113 } 114 }
E:
dp。
F:
线段树+平衡树。
G:
树型dp。
H:
高斯消元数学题。
I:
字符串题。广义后缀自动机。
J:
dp+最短路。dp[i][j]表示从起点走到编号为i的点,至多免费走j条边的花费的最小值。
dp[i][j]=min(dp[i][j-1],min(dp[x][j-1],dp[x][j]+e)) 其中点x和点i有边权为e的边。
从小到大枚举j进行转移,以min(dp[i][j-1],dp[x][j-1])作为点i距离的初始值。时间复杂度O(kmlogn)。

1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou double 6 #define pb emplace_back 7 #define mp make_pair 8 #define sot(a,b) sort(a+1,a+1+b) 9 #define rep1(i,a,b) for(int i=a;i<=b;++i) 10 #define rep0(i,a,b) for(int i=a;i<b;++i) 11 #define eps 1e-8 12 #define int_inf 0x3f3f3f3f 13 #define ll_inf 0x7f7f7f7f7f7f7f7f 14 #define lson (curpos<<1) 15 #define rson (curpos<<1|1) 16 /* namespace */ 17 using namespace std; 18 /* header end */ 19 20 const int maxn = 1e3 + 10; 21 struct Edge { 22 int u, v, w; 23 } edge[maxn << 1]; 24 int head[maxn], nxt[maxn << 1], tot = 0, dp[maxn][maxn]; 25 26 void init() { 27 tot = 0; 28 rep0(i, 0, maxn) head[i] = 0; 29 rep0(i, 0, maxn * 2) nxt[i] = 0; 30 rep0(i, 0, maxn) rep0(j, 0, maxn) dp[i][j] = int_inf; 31 } 32 33 void addEdge(int u, int v, int w) { 34 nxt[++tot] = head[u]; 35 head[u] = tot; 36 edge[tot].u = u; 37 edge[tot].v = v; 38 edge[tot].w = w; 39 } 40 41 struct Node { 42 int x, d, k; 43 Node() {} 44 Node(int a, int b, int c): x(a), d(b), k(c) {} 45 bool operator<(const Node &rhs)const { 46 return d > rhs.d; 47 } 48 }; 49 50 int dijkstra(int s, int t, int k) { 51 priority_queue<Node, vector<Node>>q; 52 dp[s][k] = 0; 53 q.push(Node(s, 0, k)); 54 while (!q.empty()) { 55 Node curr = q.top(); 56 q.pop(); 57 int u = curr.x, d = curr.d, k = curr.k; 58 if (d > dp[u][k]) continue; 59 if (u == t) return d; 60 for (int i = head[u]; i; i = nxt[i]) { 61 int v = edge[i].v, w = edge[i].w; 62 if (k && dp[v][k - 1] > d) { 63 dp[v][k - 1] = d; 64 q.push(Node(v, d, k - 1)); 65 } 66 if (dp[v][k] > d + w) { 67 dp[v][k] = d + w; 68 q.push(Node(v, d + w, k)); 69 } 70 } 71 } 72 } 73 74 int main() { 75 init(); 76 int n, m, s, t, k; scanf("%d%d%d%d%d", &n, &m, &s, &t, &k); 77 rep0(i, 0, m) { 78 int u, v, w; scanf("%d%d%d", &u, &v, &w); 79 if (u == v) continue; 80 addEdge(u, v, w); addEdge(v, u, w); 81 } 82 printf("%d ", dijkstra(s, t, k)); 83 return 0; 84 }
K:
给定一个数字序列,问:该数字序列有多少个子序列,其值能被300整除。
注意到300的整数既能被3整除又能被100整除。对于被3整除,用一个数组记录前缀和%3的结果即可;对于被100整除,判断最后两位是否都为0。

1 /* basic header */ 2 #include <bits/stdc++.h> 3 /* define */ 4 #define ll long long 5 #define dou double 6 #define pb emplace_back 7 #define mp make_pair 8 #define sot(a,b) sort(a+1,a+1+b) 9 #define rep1(i,a,b) for(int i=a;i<=b;++i) 10 #define rep0(i,a,b) for(int i=a;i<b;++i) 11 #define eps 1e-8 12 #define int_inf 0x3f3f3f3f 13 #define ll_inf 0x7f7f7f7f7f7f7f7f 14 #define lson (curpos<<1) 15 #define rson (curpos<<1|1) 16 /* namespace */ 17 using namespace std; 18 /* header end */ 19 20 // const int maxn = 1e5 + 10; 21 const int maxn = 10; 22 char s[maxn]; 23 int n, pre[maxn], cnt[3]; 24 25 int main() { 26 scanf("%s", s + 1); n = strlen(s + 1); 27 rep1(i, 1, n) pre[i] = (pre[i - 1] + s[i] - '0') % 3; 28 ll ans = 0; 29 rep1(i, 1, n) { 30 if (s[i] == '0') { 31 ans++; // 算单独0 32 if (s[i - 1] == '0') ans += cnt[pre[i - 1]]; // 如果前一位也是0,满足被100整除的要求 33 } 34 cnt[pre[i - 1]]++; 35 } 36 printf("%lld ", ans); 37 return 0; 38 }