Codeforces Round #737 (Div. 2)

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} n1i=1n1a[i] >= ∑ i = 1 k a [ i ] k \frac{\sum_{i=1}^{k}a[i]}{k} ki=1ka[i] + ∑ i = k + 1 n a [ i ] n − k − 1 \frac{\sum_{i=k+1}^{n}a[i]}{n-k-1} nk1i=k+1na[i] (1 <= k < n)
a[n] >= ∑ i = 1 k a [ i ] k \frac{\sum_{i=1}^{k}a[i]}{k} ki=1ka[i] + ∑ i = k + 1 n a [ i ] n − k − 1 \frac{\sum_{i=k+1}^{n}a[i]}{n-k-1} nk1i=k+1na[i] - ∑ i = 1 n − 1 a [ i ] n − 1 \frac{\sum_{i=1}^{n-1}a[i]}{n-1} n1i=1n1a[i]
n从小到大排序所以 ∑ i = 1 k a [ i ] k \frac{\sum_{i=1}^{k}a[i]}{k} ki=1ka[i] - ∑ i = 1 n − 1 a [ i ] n − 1 \frac{\sum_{i=1}^{n-1}a[i]}{n-1} n1i=1n1a[i] < 0
又因为 ∑ i = k + 1 n a [ i ] n − k − 1 \frac{\sum_{i=k+1}^{n}a[i]}{n-k-1} nk1i=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+...+Cnn1=2n1
    • 当前位情况为 2 n − 1 + 1 2^{n - 1} + 1 2n1+1,一共有k位,答案为qmi( 2 n − 1 + 1 2^{n - 1} + 1 2n1+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+...+Cnn2=2n11
    • 接下来考虑大于的情况,也就是当前位之前的位都相同,当前位a为1,b为0(仅当前位全为1时),且后面的所有位都可以为任意值,那么考虑这一位对答案贡献为:qmi( 2 n − 1 − 1 2^{n - 1} - 1 2n11, i - 1, mod)这是前i-1位相同时有多少种可能,再乘后n-i-1位有多少种可能qmi( 2 n − 1 2^{n} - 1 2n1, n - i - 1, mod)
    • 所以我们枚举每一位答案加上qmi( 2 n − 1 − 1 2^{n - 1} - 1 2n11, i - 1, mod) * qmi( 2 n − 1 2^{n} - 1 2n1, 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值