比赛链接
C Ubiquity
Description
设 A A A 为 N N N 个 0~9 的数构成的序列。问存在 0 且存在 9 的序列有多少个。
Solution
方法 1:所求序列个数为总序列个数减去不含 0 或不含 9 的序列个数。
不含 0 和 9 的序列个数有 8 n 8^n 8 n 个。
含 0 但不含 9 的序列个数有 9 n − 8 n 9^n - 8^n 9 n − 8 n 个。(二项式去掉第 0 项可得)
含 9 但不含 0 的序列个数同上。
所以答案为 1 0 n − 2 ∗ 9 n + 8 n 10^n - 2 * 9^n + 8^n 1 0 n − 2 ∗ 9 n + 8 n
方法 2: DP
d p [ n ] [ 0 ] [ 0 ] dp[n][0][0] d p [ n ] [ 0 ] [ 0 ] 表示当前序列长度为 n n n ,有 0 个 0, 0 个 9 的方案数
d p [ n ] [ 1 ] [ 0 ] dp[n][1][0] d p [ n ] [ 1 ] [ 0 ] 表示当前序列长度为 n n n ,有至少 1 个 0, 0 个 9 的方案数
d p [ n ] [ 0 ] [ 1 ] dp[n][0][1] d p [ n ] [ 0 ] [ 1 ] 表示当前序列长度为 n n n ,有 0 个 0, 至少 1 个 9 的方案数
d p [ n ] [ 1 ] [ 1 ] dp[n][1][1] d p [ n ] [ 1 ] [ 1 ] 表示当前序列长度为 n n n ,有至少 1 个 0,至少 1 个 9 的方案数
Code
Ubiquity 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 #include <bits/stdc++.h> #define int long long int tc, n, m;array <int , MAXN> a;inline int qpow (int a, int b) { int res = 1 ; while (b) { if (b & 1 ) res = res * a % MOD; a = a * a % MOD; b >>= 1 ; } return res; } signed main () { std ::ios::sync_with_stdio(false ), cin .tie(0 ), cout .tie(0 ); cin >> n; int res = qpow(10 , n); int minus = qpow(8 , n); (minus += 2L L * (qpow(9 , n) - qpow(8 , n))) %= MOD; (res -= minus) %= MOD; cout << (res + MOD) % MOD <<endl ; return 0 ; }
D Redistribution
Description
题目链接
Solution
首先,由于数列中每个数至少为 3,因此数列长度最大为 L = S 3 L=\frac{S}{3} L = 3 S 。设 d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 表示构成长度为 i i i ,和为 j j j 的数列方案数,那么最后答案为 ∑ i = 1 L d p [ i ] [ S ] \sum\limits_{i=1}^{L}dp[i][S] i = 1 ∑ L d p [ i ] [ S ] 。易得状态转移方程为 d p [ i ] [ j ] = ∑ k = ( i − 1 ) ∗ 3 j − 3 d p [ i − 1 ] [ k ] , j ∈ [ i ∗ 3 , S ] dp[i][j]=\sum\limits_{k=(i-1)*3}^{j-3}dp[i-1][k],j∈[i*3,S] d p [ i ] [ j ] = k = ( i − 1 ) ∗ 3 ∑ j − 3 d p [ i − 1 ] [ k ] , j ∈ [ i ∗ 3 , S ] 。如果直接转移时间复杂度为O ( S 2 L ) O(S^2L) O ( S 2 L ) ,但 ∑ k = ( i − 1 ) ∗ 3 j − 3 d p [ i − 1 ] [ k ] \sum\limits_{k=(i-1)*3}^{j-3}dp[i-1][k] k = ( i − 1 ) ∗ 3 ∑ j − 3 d p [ i − 1 ] [ k ] 可以用利用前缀和 O ( 1 ) O(1) O ( 1 ) 求得,同时 d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 第一维可以滚掉,因此复杂度可降至 O ( S L ) O(SL) O ( S L ) 。
Code
Redistribution 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 #include <bits/stdc++.h> using namespace std ;const int MOD = 1E9 + 7 ;int dp[2005 ], sum[2005 ];int len, s, ans;template <class T >void read (T &x , T f = 1, char ch = getchar ()) { x = 0 ; while (ch < '0' || ch > '9' ) f = (ch == '-' ? -1 : 1 ), ch = getchar(); while (ch >= '0' && ch <= '9' ) x = x * 10 + ch - 48 , ch = getchar(); x *= f; } int main () { cin >> s; len = s / 3 ; dp[0 ] = 1 ; for (int i = 0 ; i <= s; i++) sum[i] = 1 ; for (int i = 1 ; i <= len; i++) { for (int j = i * 3 ; j <= s; j++) dp[j] = (sum[j - 3 ] - (i > 1 ? sum[(i - 1 ) * 3 - 1 ] : 0 )) % MOD; ans += dp[s], ans %= MOD; for (int j = 0 ; j <= s; j++) sum[j] = 0 ; for (int j = i * 3 - 1 ; j <= s; j++) sum[j] = (sum[j - 1 ] + dp[j]) % MOD; } cout << (ans + MOD) % MOD; return 0 ; }
E Dist Max
Description
题目链接
Solution
∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ |x_1-x_2|+|y_1-y_2| ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ 去绝对值后有以下四种情况:
x 1 + y 1 − ( x 2 + y 2 ) x_1+y_1-(x_2+y_2) x 1 + y 1 − ( x 2 + y 2 )
y 1 − x 1 − ( y 2 − x 2 ) y_1-x_1-(y_2-x_2) y 1 − x 1 − ( y 2 − x 2 )
x 2 + y 2 − ( x 1 + y 1 ) x_2+y_2-(x_1+y_1) x 2 + y 2 − ( x 1 + y 1 )
y 2 − x 2 − ( y 1 − x 1 ) y_2-x_2-(y_1-x_1) y 2 − x 2 − ( y 1 − x 1 )
要求 ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ |x_1-x_2|+|y_1-y_2| ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ 最大值,只需要分别求出 x i + y i x_i+y_i x i + y i 和 y i − x i y_i-x_i y i − x i 最大值与最小值的差,对这两个差取 m a x max m a x 即可。
Code
Dist Max 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 #include <bits/stdc++.h> using namespace std ;int n, x, y;int mxSum = INT_MIN, miSum = INT_MAX, mxSub = INT_MIN, miSub = INT_MAX;template <class T >void read (T &x , T f = 1, char ch = getchar ()) { x = 0 ; while (ch < '0' || ch > '9' ) f = (ch == '-' ? -1 : 1 ), ch = getchar(); while (ch >= '0' && ch <= '9' ) x = x * 10 + ch - 48 , ch = getchar(); x *= f; } int main () { read(n); for (int i = 1 ; i <= n; i++) { read(x), read(y); mxSum = max(mxSum, x + y), miSum = min(miSum, x + y); mxSub = max(mxSub, y - x), miSub = min(miSub, y - x); } cout << max(mxSum - miSum, mxSub - miSub); return 0 ; }
E Contrast
Description
题目链接
Solution
首先根据鸽巢原理,如果一个数在 A A A 和 B B B 的出现次数大于 n n n ,那么一定无解。
对于有解的情况,设 C i C_i C i 表示 A A A 中小于等于 i i i 的数的个数,设 D i D_i D i 表示 B B B 中小于等于 i i i 的数的个数,C i C_i C i , D i D_i D i 是单增的。
对于每一个 x ( 0 ≤ x ≤ N ) x(0 \leq x \leq N) x ( 0 ≤ x ≤ N ) ,我们让 B B B 的每个元素向右移动 x x x 位(即将 B i + 1 B_{i+1} B i + 1 移动到 B ( i + x ) % n + 1 B_{(i+x) \% n+1} B ( i + x ) % n + 1 )。
要使结果合法,x x x 需要满足对于所有 i ( 1 ≤ i ≤ n ) i(1 \leq i \leq n) i ( 1 ≤ i ≤ n ) ,区间( C i − 1 , C i ] (C_{i-1}, C_{i}] ( C i − 1 , C i ] ,( x + D i − 1 , x + D i ] (x + D_{i - 1}, x + D_{i}] ( x + D i − 1 , x + D i ] 和 ( n + C i − 1 , n + C i ] (n + C_{i-1}, n + C_{i}] ( n + C i − 1 , n + C i ] 没有交集(可以看作 A A A 复制一倍,B B B 右移 x x x ,需满足同一位置没有相同的数)。即对于所有 i i i , C i − D i − 1 ≤ x ≤ C i − 1 + n − D i C_i - D_{i-1} \leq x \leq C_{i-1}+n-D_i C i − D i − 1 ≤ x ≤ C i − 1 + n − D i 。
可以证明这样的 x x x 是一定存在的Editorial 。
由于对于每一个 i i i 都要成立,则 x x x 的取值范围一定在 C i − D i − 1 C_i - D_{i-1} C i − D i − 1 的最大值 与 C i − 1 + n − D i C_{i-1}+n-D_i C i − 1 + n − D i 的最小值之间。故取 x x x 为 C i − D i − 1 C_i - D_{i-1} C i − D i − 1 的最大值即可。
Code
Contrast 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 #include <bits/stdc++.h> using namespace std ;constexpr int MAXN = 2e5 + 5 ;int n, mx;array <int , MAXN> a, b, c, d, cnt, ans;int main () { ios::sync_with_stdio(false ), cin .tie(0 ), cout .tie(0 ); cin >> n; for (int i = 1 ; i <= n; i++) cin >> a[i], c[a[i]]++, cnt[a[i]]++; for (int i = 1 ; i <= n; i++) c[i] += c[i - 1 ]; for (int i = 1 ; i <= n; i++) cin >> b[i], d[b[i]]++, cnt[b[i]]++; for (int i = 1 ; i <= n; i++) d[i] += d[i - 1 ]; for (int i = 1 ; i <= n; i++) if (cnt[i] > n) { cout << "No" << endl ; return 0 ; } for (int i = 1 ; i <= n; i++) mx = max(mx, c[i] - d[i - 1 ]); for (int i = 1 ; i <= n; i++) ans[(i + mx) % n == 0 ? n : (i + mx) % n] = b[i]; cout << "Yes" << endl ; for (int i = 1 ; i <= n; i++) cout << ans[i] << " " ; return 0 ; }