A Ezzat and Two Subsequences
题目大意
给定一个长度为n的数组,让你把数组中的数任意分成两部分,使得两部分的平均值的和最大,求这个最大值
主要思路
先给结论,取最大的数为一部分,剩下的数为一部分,下面给出证明,先将数组从小到大排序
a[n] + ∑ i = 1 n − 1 a [ i ] n − 1 \frac{\sum_{i=1}^{n-1}a[i]}{n-1} n−1∑i=1n−1a[i] >= ∑ i = 1 k a [ i ] k \frac{\sum_{i=1}^{k}a[i]}{k} k∑i=1ka[i] + ∑ i = k + 1 n a [ i ] n − k − 1 \frac{\sum_{i=k+1}^{n}a[i]}{n-k-1} n−k−1∑i=k+1na[i] (1 <= k < n)
a[n] >= ∑ i = 1 k a [ i ] k \frac{\sum_{i=1}^{k}a[i]}{k} k∑i=1ka[i] + ∑ i = k + 1 n a [ i ] n − k − 1 \frac{\sum_{i=k+1}^{n}a[i]}{n-k-1} n−k−1∑i=k+1na[i] - ∑ i = 1 n − 1 a [ i ] n − 1 \frac{\sum_{i=1}^{n-1}a[i]}{n-1} n−1∑i=1n−1a[i]
n从小到大排序所以 ∑ i = 1 k a [ i ] k \frac{\sum_{i=1}^{k}a[i]}{k} k∑i=1ka[i] - ∑ i = 1 n − 1 a [ i ] n − 1 \frac{\sum_{i=1}^{n-1}a[i]}{n-1} n−1∑i=1n−1a[i] < 0
又因为 ∑ i = k + 1 n a [ i ] n − k − 1 \frac{\sum_{i=k+1}^{n}a[i]}{n-k-1} n−k−1∑i=k+1na[i] 一定小于a[n]所以式子一定成立
AC代码
#include <bits/stdc++.h>
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 100010;
ll n, a[N];
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n;
ll sum = 0, maxa = -1e9;
for(int i = 0; i < n; i++) cin >> a[i], sum += a[i], maxa = max(maxa, a[i]);
printf("%.9lf\n", (sum - maxa) * 1.0 / (n - 1) + 1.0 * maxa);
}
return 0;
}
B Moamen and k-subarrays
题目大意
给定一个长度为n的数组,问能否将数组分为k份,使得这k份数组能拼成一个有序数组
主要思路
考虑使得这k份数组能拼成一个有序数组后数组是什么样的,一定是数组下标至多k段是连续的
于是我们对原数组进行操作,保存值的同时保存数组下标,然后带着数组下标排序,看排序后的数组下标有多少不连续的段如果大于k输出no
AC代码
#include <bits/stdc++.h>
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 100010;
int n, k;
pair<int, int> p[N];
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n >> k;
for(int i = 0; i < n; i++) cin >> p[i].x, p[i].y = i;
sort(p, p + n);
int cnt = 1;
int t = p[0].y;
for(int i = 1; i < n; i++)
{
if(p[i].y == t + 1)
{
t++;
}
else
{
cnt++;
t = p[i].y;
}
}
if(cnt > k) puts("No");
else puts("Yes");
}
return 0;
}
C Moamen and XOR
题目大意
给两个数n和k,问满足 a1 & a2 & a3 … & an >= a1 ^ a2 ^ a3 … ^ an ( 0 <= a[i] <= 2^k )的有多少种数组
主要思路
奇数个1异或结果为1,偶数个1异或结果为0,所以先考虑n为奇数还是偶数
-
令a = a1 & a2 & a3 … & an, b = a1 ^ a2 ^ a3 … ^ an
-
n为奇数时,不存在a大于b的情况,因为当前a的某1位全1的情况跟异或时相等,所以只需考虑相同情况即可,只考虑一位时
- 当前组成a,b的这一位全1
- 或者是偶数个1,奇数个0,个数为 C n 0 + C n 2 + . . . + C n n − 1 = 2 n − 1 C_n^0 + C_n^2 + ... + C_n^{n-1} = 2^{n-1} Cn0+Cn2+...+Cnn−1=2n−1
- 当前位情况为 2 n − 1 + 1 2^{n - 1} + 1 2n−1+1,一共有k位,答案为qmi( 2 n − 1 + 1 2^{n - 1} + 1 2n−1+1, k, mod)
-
n为偶数时,存在a大于b的情况
- 先考虑a, b相等的情况与奇数情况类似,只不过当全1时不相同,且 C n 0 + C n 2 + . . . + C n n − 2 = 2 n − 1 − 1 C_n^0 + C_n^2 + ... + C_n^{n-2} = 2^{n-1} - 1 Cn0+Cn2+...+Cnn−2=2n−1−1
- 接下来考虑大于的情况,也就是当前位之前的位都相同,当前位a为1,b为0(仅当前位全为1时),且后面的所有位都可以为任意值,那么考虑这一位对答案贡献为:qmi( 2 n − 1 − 1 2^{n - 1} - 1 2n−1−1, i - 1, mod)这是前i-1位相同时有多少种可能,再乘后n-i-1位有多少种可能qmi( 2 n − 1 2^{n} - 1 2n−1, n - i - 1, mod)
- 所以我们枚举每一位答案加上qmi( 2 n − 1 − 1 2^{n - 1} - 1 2n−1−1, i - 1, mod) * qmi( 2 n − 1 2^{n} - 1 2n−1, n - i - 1, mod),最后加上a与b相同的情况
AC代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 100010, mod = 1e9+7;
int qmi(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(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while(T--)
{
int n, k;
cin >> n >> k;
int t = qmi(2, n - 1);
int ans = 1;
if(n % 2)
{
ans = qmi(t + 1, k);
}
else
{
ans = qmi(t - 1, k);
for(int i = 1; i <= k; i++)
{
ans = (ans + qmi(t - 1, i - 1) * qmi(t * 2, k - i) % mod) % mod;
}
}
cout << ans << endl;
}
return 0;
}