Codeforces Round #737 (Div. 2)
A
容易發現,若將數列中的最大值與其他元素分在一起,只會使其貢獻減少。
由於只能分成 \(2\) 個非空子序列,我們將最大值劃分到其中一個,剩下的元素劃分到另一個即可。
程式碼:
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; typedef long long ll; int a[100007]; int main(){ int t; cin >> t; for (int i = 1; i <= t; i++){ int n; ll sum = 0; cin >> n; for (int j = 1; j <= n; j++){ cin >> a[j]; sum += a[j]; } sort(a + 1, a + n + 1); printf("%.8lf\n", a[n] + 1.0 * (sum - a[n]) / (n - 1)); } return 0; }
B
根據題目要求,可以發現離散化後值的大小相鄰者如果不挨在一起,則需要新增一個子串。
證明:加上它們不挨在一起時不需要新增子串,則將整個序列劃分完後較大的值插不進來,會導致排序失敗。
統計子串個數,若個數 \(\leq k\) 輸出 Yes
,否則輸出 No
即可。
程式碼:
#include <iostream> #include <algorithm> using namespace std; typedef long long ll; int a[100007], b[100007], pos[100007]; int main(){ int t; cin >> t; pos[0] = -1; for (int i = 1; i <= t; i++){ int n, k, cnt = 0; cin >> n >> k; for (int j = 1; j <= n; j++){ cin >> a[j]; b[j] = a[j]; } sort(b + 1, b + n + 1); for (int j = 1; j <= n; j++){ a[j] = lower_bound(b + 1, b + n + 1, a[j]) - b; pos[a[j]] = j; } for (int j = 1; j <= n; j++){ if (pos[j] != pos[j - 1] + 1) cnt++; } if (cnt <= k){ cout << "Yes" << endl; } else { cout << "No" << endl; } } return 0; }
C
做了這道題我才知道——我不會數數,我甚至不配數數。
顯然,我們並不關心陣列中每個數的實際值,我們只關心 \(\operatorname{and}\) 和 \(\operatorname{xor}\) 運算後得到的值。設 \(\operatorname{and}\) 得到的值為 \(a\),\(\operatorname{xor}\) 得到的值為 \(b\)。
設 \(dp_{i, j}\) 表示從第 \(0\) 位(即最高位)到第 \(i\) 位構造原陣列的方法數。若 \(j = 0\),此時 \(a > b\);否則,此時 \(a = b\)。
初始值:\(dp_{-1, 0} = dp_{-1, 1} = 1\)
答案:\(dp_{k - 1, 1}\)。
轉移:
- 當 \(j = 0\)
顯然 \(dp_{i, j} = 2^n dp_{i - 1, j}\)。
- 當 \(j = 1 \operatorname{and} n \bmod 2 = 0\)
- 你可以讓這位為 \(1\) 的元素數量為偶數(當然,不能為 \(n\)),此時 \(a = b\);
- 你可以讓這位為 \(1\) 的元素數量為 \(n\),此時 \(a > b\)。
令 \(x = \displaystyle\sum_{i = 0}^{\lfloor \frac{n - 1}{2} \rfloor} C_n^{2i}\),則 \(dp_{i, j} = x dp_{i - 1, 1} + dp_{i - 1, 0}\)。
- 當 \(j = 1 \operatorname{and} n \bmod 2 \neq 0\)
- 你可以讓這位為 \(1\) 的元素數量為偶數,此時 \(a = b\);
- 你可以讓這位為 \(1\) 的元素數量為 \(n\),此時仍然 \(a = b\)。
則 \(dp_{i, j} = (x + 1) dp_{i - 1, 1}\)。
預處理組合數後直接轉移即可。注意需要特判 \(k = 0\) 的情況。
程式碼:
#include <stdio.h>
typedef long long ll;
const int N = 2e5 + 7, M = 1 + 7, mod = 1e9 + 7;
ll fac[N], inv_fac[N], dp[N][M];
inline ll quick_pow(ll x, ll p, ll mod){
ll ans = 1;
while (p){
if (p & 1) ans = ans * x % mod;
x = x * x % mod;
p >>= 1;
}
return ans;
}
inline void init(){
fac[0] = 1;
for (int i = 1; i < N; i++){
fac[i] = fac[i - 1] * i % mod;
}
inv_fac[N - 1] = quick_pow(fac[N - 1], mod - 2, mod);
for (int i = N - 2; i >= 0; i--){
inv_fac[i] = inv_fac[i + 1] * (i + 1) % mod;
}
}
inline ll comb(ll n, ll m, ll mod){
if (m == 0) return 1;
if (m > n) return 0;
return fac[n] * inv_fac[m] % mod * inv_fac[n - m] % mod;
}
int main(){
int t;
scanf("%d", &t);
init();
for (int i = 1; i <= t; i++){
int n, k;
scanf("%d %d", &n, &k);
if (k == 0){
printf("1\n");
continue;
}
ll x = 0, ans;
for (int j = 0; j < n; j += 2){
x = (x + comb(n, j, mod)) % mod;
}
if (n % 2 == 0){
ll y = dp[0][0] = quick_pow(2, n, mod);
dp[0][1] = x + 1;
for (int j = 1; j < k; j++){
int jd = j - 1;
dp[j][0] = y * dp[jd][0] % mod;
dp[j][1] = (x * dp[jd][1] % mod + dp[jd][0]) % mod;
}
ans = dp[k - 1][1];
} else {
ans = quick_pow(x + 1, k, mod);
}
printf("%lld\n", ans);
}
return 0;
}