It has been 923 days since the last update, the content of the article may be outdated.
百度之星2021复赛游记我emo了...
400名有T恤穿,我403啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
T1 题目概述给一个长度为 n n n 的序列,求怎么分割后每一段的 x o r xor x o r 值最大,输出这个最大值
思路显然,每个数为一段最大,答案为每个数的和
CodeCode 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <bits/stdc++.h> using namespace std;#define int long long #define ull unsigned long long #define ALL(a) (a).begin(), (a).end() #define pb push_back #define mk make_pair #define pii pair<int, int> #define pis pair<int, string> #define sec second #define fir first #define sz(a) int((a).size()) #define rep(i, x, y) for (int i = x; i <= y; i++) #define repp(i, x, y) for (int i = x; i >= y; i--) #define Yes cout << "Yes" << endl #define YES cout << "YES" << endl #define No cout << "No" << endl #define NO cout << "NO" << endl #define debug(x) cerr << #x << ": " << x << endl #define double long double const int INF = 0x3f3f3f3f ;const int MOD = 1000000007 ;const int N = 2e5 + 10 ;int n;int a[N];int res = 0 ;signed main () { cin >> n; for (int i = 1 ; i <= n; i++) cin >> a[i], res += a[i]; cout << res << endl; return 0 ; }
花絮第一眼以为 T 1 T1 T 1 不是签到,所以等600多人 A C \color{green}{AC} A C 我才 A C \color{green}{AC} A C
T3 题目概述长度为n n n ,且元素为 1 1 1 ~ m m m 的序列的贡献为等于序列最大值的元素个数,求所有序列的贡献之和
1 ≤ n ⋅ m ≤ 1 0 12 1 \leq n \cdot m \leq 10^{12} 1 ≤ n ⋅ m ≤ 1 0 1 2
思路对于一个受过良好义务教育 的小学生来说,很明显,答案为
r e s = n ⋅ ∑ i = 1 m i n − 1 res=n\cdot \sum^{m}_{i=1}{i^{n-1}} r e s = n ⋅ i = 1 ∑ m i n − 1 然后,会发现,这玩意暴力算会 T L E \color{red}{TLE} T L E ,所以,回到数据范围,发现可以分 m < n m<n m < n 和 m ≥ n m\geq n m ≥ n 讨论
那么,如果m m m 较小,显然快速幂+暴力就能过
而如果m m m 较大,我们则希望计算的复杂度为 O ( N ) O(N) O ( N ) , 此时,可以使用拉格朗日插值 来进行计算
CodeCode 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 #include <bits/stdc++.h> using namespace std;#define int long long #define ull unsigned long long #define ALL(a) (a).begin(), (a).end() #define pb push_back #define mk make_pair #define pii pair<int, int> #define pis pair<int, string> #define sec second #define fir first #define sz(a) int((a).size()) #define rep(i, x, y) for (int i = x; i <= y; i++) #define repp(i, x, y) for (int i = x; i >= y; i--) #define Yes cout << "Yes" << endl #define YES cout << "YES" << endl #define No cout << "No" << endl #define NO cout << "NO" << endl #define debug(x) cerr << #x << ": " << x << endl #define double long double const int INF = 0x3f3f3f3f ;const int MOD = 998244353 ;const int N = 3e6 + 10 ;int k, tab[N], p[N], pcnt, f[N], pre[N], suf[N], fac[N], inv[N], ans;int quickMod (int a, int b) { int ans = 1 ; while (b) { if (b & 1 ) ans = ans * a % MOD; a = a * a % MOD; b >>= 1 ; } return ans; } void sieve (int lim) { f[1 ] = 1 ; for (int i = 2 ; i <= lim; i++) { if (!tab[i]) { p[++pcnt] = i; f[i] = quickMod (i, k); } for (int j = 1 ; j <= pcnt && 1LL * i * p[j] <= lim; j++) { tab[i * p[j]] = 1 ; f[i * p[j]] = 1LL * f[i] * f[p[j]] % MOD; if (!(i % p[j])) break ; } } for (int i = 2 ; i <= lim; i++) f[i] = (f[i - 1 ] + f[i]) % MOD; } int cal (int n) { ans = 0 ; if (n <= k + 2 ) return f[n]; pre[0 ] = suf[k + 3 ] = 1 ; for (int i = 1 ; i <= k + 2 ; i++) pre[i] = 1LL * pre[i - 1 ] * (n - i) % MOD; for (int i = k + 2 ; i >= 1 ; i--) suf[i] = 1LL * suf[i + 1 ] * (n - i) % MOD; fac[0 ] = inv[0 ] = fac[1 ] = inv[1 ] = 1 ; for (int i = 2 ; i <= k + 2 ; i++) { fac[i] = 1LL * fac[i - 1 ] * i % MOD; inv[i] = 1LL * (MOD - MOD / i) * inv[MOD % i] % MOD; } for (int i = 2 ; i <= k + 2 ; i++) inv[i] = 1LL * inv[i - 1 ] * inv[i] % MOD; for (int i = 1 ; i <= k + 2 ; i++) { int P = 1LL * pre[i - 1 ] * suf[i + 1 ] % MOD; int Q = 1LL * inv[i - 1 ] * inv[k + 2 - i] % MOD; int mul = ((k + 2 - i) & 1 ) ? -1 : 1 ; ans = (ans + 1LL * (Q * mul + MOD) % MOD * P % MOD * f[i] % MOD) % MOD; } return ans; } signed main () { int a, b; cin >> a >> b; k = a - 1 ; int res = 0 ; if (b < a) { for (int i = 1 ; i <= b; i++) { (res += quickMod (i, a - 1 )) %= MOD; } cout << res * a % MOD << endl; return 0 ; } else { sieve (k + 2 ); cout << a * cal (b) % MOD << endl ; } return 0 ; }
T4 题目概述给定一个长度为 n n n 的序列,和 q q q 个查询
每次查询有 k , l , r k,l,r k , l , r ,求 a [ l , . . . , r ] a[l,...,r] a [ l , . . . , r ] 中有多少个子序列 a b 1 , a b 2 , ⋯ , a b p a_{b_1},a_{b_2},\cdots ,a_{b_p} a b 1 , a b 2 , ⋯ , a b p 满足 i ∈ [ 1 , p ) i\in [1,p) i ∈ [ 1 , p ) , a b i < k ≤ a b i + 1 a_{b_i}<k \leq a_{b_{i+1}} a b i < k ≤ a b i + 1 或 a b i + 1 < k ≤ a b i a_{b_{i+1}} < k \leq a_{b_{i}} a b i + 1 < k ≤ a b i
思路先转化题意,即对于每个询问,把区间内大于等于 k k k 的数记为 1 1 1 , 小于的记为 0 0 0
很明显可以通过d p dp d p , O ( N ) O(N) O ( N ) 的解决每个询问
但是上面的方法并不能满足时间限制,所以可以考虑通过线段树来代替d p dp d p
线段树上存 4 4 4 个数,分别表示当前区间中开头为 0 / 1 0/1 0 / 1 , 结尾为 0 / 1 0/1 0 / 1 的情况,这样就可以做 p u s h u p pushup p u s h u p 了
但是此时仍然需要 O ( N ) O(N) O ( N ) 去检查哪些需要 u p d a t e update u p d a t e , 考虑先对询问的按 k k k 排序,并对原数组排序
按顺序执行询问时,每个数最多被修改一次,每次修改的复杂度为 O ( l o g n ) O(logn) O ( l o g n ) .
由于事先对原数组排序,所以可以通过二分求出修改的起点和终点
所以最终的复杂度为 O ( n l o g n ) O(nlogn) O ( n l o g n ) ,注意常数问题
CodeCode 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 #include <bits/stdc++.h> using namespace std;#define int long long #define ull unsigned long long #define ALL(a) (a).begin(), (a).end() #define pb push_back #define mk make_pair #define pii pair<int, int> #define pis pair<int, string> #define sec second #define fir first #define sz(a) int((a).size()) #define rep(i, x, y) for (int i = x; i <= y; i++) #define repp(i, x, y) for (int i = x; i >= y; i--) #define Yes cout << "Yes" << endl #define YES cout << "YES" << endl #define No cout << "No" << endl #define NO cout << "NO" << endl #define debug(x) cerr << #x << ": " << x << endl #define double long double const int INF = 0x3f3f3f3f ;const int MOD = 1000000007 ;const int N = 2e5 + 10 ;#define ls u << 1 #define rs u << 1 | 1 int n, q;int a[N];pii b[N]; struct Node { int l, r; int zz = 0 , zo = 0 , oz = 0 , oo = 0 ; Node operator +(Node y) const { Node res; res.zz = zz + y.zz + zz * y.oz + zo * y.zz; res.zo = zo + y.zo + zz * y.oo + zo * y.zo; res.oo = oo + y.oo + oz * y.oo + oo * y.zo; res.oz = oz + y.oz + oz * y.oz + oo * y.zz; return res; } } tr[N * 4 ]; void pushup (int u) { tr[u].zz = tr[ls].zz + tr[rs].zz + tr[ls].zz * tr[rs].oz + tr[ls].zo * tr[rs].zz; tr[u].zo = tr[ls].zo + tr[rs].zo + tr[ls].zz * tr[rs].oo + tr[ls].zo * tr[rs].zo; tr[u].oo = tr[ls].oo + tr[rs].oo + tr[ls].oz * tr[rs].oo + tr[ls].oo * tr[rs].zo; tr[u].oz = tr[ls].oz + tr[rs].oz + tr[ls].oz * tr[rs].oz + tr[ls].oo * tr[rs].zz; } void build (int u, int l, int r) { if (l == r) { tr[u].l = l; tr[u].r = r; tr[u].oo = 1 ; tr[u].oz = 0 ; tr[u].zo = 0 ; tr[u].zz = 0 ; } else { tr[u].l = l; tr[u].r = r; int mid = l + r >> 1 ; build (u << 1 , l, mid); build (u << 1 | 1 , mid + 1 , r); pushup (u); } } void update (int u, int p, int d) { if (tr[u].l == tr[u].r) { tr[u].oo = tr[u].oz = tr[u].zo = tr[u].zz = 0 ; if (d == 1 ) tr[u].oo = 1 ; else tr[u].zz = 1 ; return ; } else { int mid = tr[u].l + tr[u].r >> 1 ; if (p <= mid) update (u << 1 , p, d); if (p > mid) update (u << 1 | 1 , p, d); pushup (u); } } Node query (int u, int l, int r) { if (tr[u].l >= l && tr[u].r <= r) { return tr[u]; } else { int mid = tr[u].l + tr[u].r >> 1 ; Node res = {1 , 1 , 0 , 0 , 0 , 0 }; if (l <= mid) res = res + query (u << 1 , l, r); if (r > mid) res = res + query (u << 1 | 1 , l, r); return res; } } struct que { int k, l, r; int id; } s[N]; int res[N];bool cmp (que a, que b) { return a.k < b.k; } signed main () { cin >> n >> q; for (int i = 1 ; i <= n; i++) { cin >> a[i]; b[i] = {a[i], i}; } sort (b + 1 , b + n + 1 ); build (1 , 1 , n); for (int i = 1 ; i <= q; i++) { cin >> s[i].k >> s[i].l >> s[i].r; s[i].id = i; } sort (s + 1 , s + q + 1 , cmp); int now = 1 ; for (int i = 1 ; i <= q; i++) { if (s[i].k != s[i - 1 ].k) { pii x = {s[i].k, -1 }; int en = upper_bound (b + 1 , b + n + 1 , x) - b; for (int j = now; j < en; j++) { update (1 , b[j].sec, 0 ); } now = en; } Node x = query (1 , s[i].l, s[i].r); res[s[i].id] = x.oo + x.oz + x.zo + x.zz; } for (int i = 1 ; i <= q; i++) cout << res[i] << endl; return 0 ; }
花絮赛后一分钟调完qwq
祭