1. 程式人生 > 其它 >Codeforces Round #737 (Div. 2)A~C

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;
}