Codeforces Round #737 (Div. 2)A~C
A. Ezzat and Two Subsequences
題意:將n個數分為兩組不為空的數的集合,輸出兩組數中平均數和的最大值,誤差不超過1e-6
分析:首先進行所有數全是正數的討論,一組為單個的最大值,右邊為剩餘n-1個的值,從右邊拿出比平均值大的數放左邊,兩邊平均值都會下降,從右邊拿出比平均值小的數,右邊會微量提高,左邊會降極多,故不換最優,而對於有負數的情況,我們總可以將所有數加一個值使得所有數變為正數,而平均值是不會有影響的,加上的值最後減去,所以同理,故結論就是,兩組分為單個最大的值,和其他所有元素,這樣分最優。
程式碼:
#include <cstring> #include <iostream> #include <algorithm> #include <map> #include <vector> #define x first #define y second using namespace std; typedef long long ll; typedef pair<int, int> PII; const int N = 1e5 + 10, mod = 1e9 + 7; int n, m, t, k, a; int s[N], g[N], dp[N]; void solve() { cin >> n; for (int i = 1; i <= n; i++) cin >> s[i]; sort(s + 1, s + n + 1); ll sum = 0; for (int i = 1; i < n; i++) sum += s[i]; printf("%.9f\n", 1.0 * sum / (n - 1) + s[n]); } int main() { t = 1; cin >> t; while(t--) solve(); return 0; }
B. Moamen and k-subarrays
題意:要將給定的n個數分為k組,使得將k組排序後,所有數成非遞減序列,題目保證所有數都不相同
分析:顯然直接將原陣列排序,儲存下每個數後面應該是哪個數,就可以在原陣列中查詢當前是否必須分割,不是必須分割就不分,會得出最少需要分割幾組才會使得排序後原陣列非遞減,顯然當最小組數大於k時,不成立,小於等於k時,再次分割,一定可以等於k組
程式碼:
#include <cstring> #include <iostream> #include <algorithm> #include <unordered_map> #include <vector> #define x first #define y second using namespace std; typedef long long ll; typedef pair<int, int> PII; const int N = 1e5 + 10, mod = 1e9 + 7; int n, m, t, k, a; int s[N], g[N], dp[N]; unordered_map<int, int> ma; void solve() { cin >> n >> k; ma.clear(); for (int i = 1; i <= n; i++) cin >> s[i], g[i] = s[i]; sort(s + 1, s + 1 + n); s[n+1] = mod; for (int i = 1; i <= n; i++) ma[s[i]] = s[i+1]; int cnt = 1; for (int i = 2; i <= n; i++) if (ma[g[i-1]] != g[i]) cnt++; if (cnt <= k) puts("Yes"); else puts("No"); } int main() { t = 1; cin >> t; while(t--) solve(); return 0; }
C. Moamen and XOR
題意:給定n和k,意義為由n個數,每個數嚴格小於\(2^{k}\),問有多少數滿足:
a1&a2&a3&…&an≥a1⊕a2⊕a3⊕…⊕an,答案取模1e9+7
分析:如果k為0,沒得討論,所有數唯一,絕對成立,輸出1即可,然後要根據大小原理,要根據最高位進行分析,當最高位全1時,前者的結果為1,後者的結果根據奇偶性為1或0,所以要分類討論,首先討論奇數的情況,奇數時,全1的話,前後的這一位都是1,然後討論前後均為0的情況,顯然,均為0的情況就是這一位有偶數個1,所以列舉\(\sum_{0}^{n/2}C_{n}^{2i}\),等於的情況就是都為1和都為0的情況,因為前者在奇數的情況下不可能大於後者,所以只有等於的情況,而所有位置情況相同,就是k個ans相乘,快速冪算一下就好,接下來討論偶數的情況,全1的話,必勝,當前數量乘後面所有位置任意排列的情況數,不必勝的時候討論當前平局,勝利狀態轉移到下一輪進行,到某一位就計算當前行全為1,的必勝情況數,疊加一起,最後要加上平局的情況數,計算過程中取模
程式碼:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 1e9 + 7;
int n, m, t, k, a;
int s[N], g[N], in[N], inv[N];
int ksm(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
void init()
{
in[0] = in[1] = inv[1] = inv[0] = 1;
for (int i = 2; i < N; i++)
{
in[i] = 1ll * in[i-1] * i % mod;
inv[i] = 1ll * inv[i-1] * ksm(i, mod - 2) % mod;
}
}
int C(int a, int b)
{
if (b == 0) return 1;
return 1ll * in[a] * inv[a-b] % mod * inv[b] % mod;
}
void solve()
{
cin >> n >> k;
if (k == 0)
{
puts("1");
return;
}
int ans = 0, cnt = 0;
if (n & 1)
{
cnt++;
for (int i = 0; i < n; i += 2)
cnt = (cnt + C(n, i)) % mod;
cout << ksm(cnt, k) << endl;
}
else
{
for (int i = 0; i < n; i += 2)
cnt = (cnt + C(n, i)) % mod;
g[0] = 1;
int cnt3 = ksm(2, n), cnt4 = 1;
for (int i = 1; i <= k; i++)
g[i] = 1ll * g[i-1] * cnt3 % mod;
int cnt2 = 1;
for (int i = 1; i <= k; i++)
{
ans = (1ll * ans + 1ll * cnt2 * g[k-i] % mod) % mod;
cnt2 = 1ll * cnt2 * cnt % mod;
}
cout << (1ll * ans + cnt2) % mod << endl;
}
}
int main()
{
init();
t = 1;
cin >> t;
while(t--)
solve();
return 0;
}