零点工作室暑假集训(Codeforces Round 882 (Div. 2))

A. The Man who became a God

题意:Kars是个顶尖的发明家,他对村庄里狭隘的思维方式感到厌倦和愤怒,因为村民们满足于现状,不努力成为完美的生命形式。Kars希望通过改造自己的身体成为完美的生命形式。然而,有n位村民对他的想法持怀疑态度。第i位村民对他抱有ai的怀疑。每位村民个别地都害怕Kars,所以他们组成团体以增强力量。 从l到r的村民团体的力量定义为f(l,r),其中 f(l,r)=|al−al+1|+|al+1−al+2|+…+|ar−1−ar|。 这里|x−y|表示x-y的绝对值。只有一位村民的团体力量为0。 Kars想要将村民分成恰好k个连续的子团体,使得它们的力量之和最小化。具体来说,他需要找到k-1个正整数1≤r1<r2<…<rk−1<n,使得f(1,r1)+f(r1+1,r2)+…+f(rk−1+1,n)达到最小值。帮助Kars找出f(1,r1)+f(r1+1,r2)+…+f(rk−1+1,n)的最小可能值。
输入:
第一行包含一个整数t(1≤t≤100)——测试用例的数量。下面是每个测试用例的描述。 每个测试用例的第一行包含两个整数n和k(1≤k≤n≤100)——村民的数量和他们必须分成的团体数。 每个测试用例的第二行包含n个整数a1,a2,…,an(1≤ai≤500)——每位村民的怀疑程度。
输出:
对于每个测试用例,输出一个整数——所有团体力量之和的最小可能值,即f(1,r1)+f(r1+1,r2)+…+f(rk−1+1,n)的最小可能值。

思路:求出相邻两个元素的差值,去掉前m个大的差值以后的差值和即位答案。

AC代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
 
using namespace std;
 
const int N = 110;
 
int t, n, k, sum;
int a[N], b[N], c[N];
 
int main()
{
    cin >> t;
    while(t --)
    {
        cin >> n >> k;
        for(int i = 1; i <= n; i ++)
        {
            cin >> a[i];
        }
    
        for(int i = 1; i <= n; i ++)
        {
            b[i] = abs(a[i + 1] - a[i]);
        }
        
        for(int i = 1; i <= n - 1; i ++)
        {
            c[i] = b[i];
        }
        
        sort(c, c + n);
    
        for(int i = 1; i <= n - k; i ++)
        {
            sum += c[i];
        }
    
        cout << sum << endl;
        sum = 0;
        
    }
    
    return 0;
}

B. Hamon Odyssey

题意:Jonathan正在与DIO的吸血鬼手下战斗。有n个吸血鬼,他们的力量分别为a1,a2,…,an。
用(l,r)表示由索引从l到r的吸血鬼组成的组。Jonathan意识到,任何这样的组的力量取决于它们最弱的环节,即按位与操作的结果。更正式地说,组(l,r)的强度等级定义为f(l,r) = al & al+1 & al+2 & … & ar。其中,&表示按位与操作。
因为Jonathan想要快速击败吸血鬼手下,他会将吸血鬼分成连续的组,使得每个吸血鬼恰好属于一个组,并且各组的力量总和最小。在所有可能的分组方式中,他希望找到分组数量最多的方式。
给定每个吸血鬼的力量,找到在所有可能的分组方式中具有最小力量总和的最大分组数量。
输入:
第一行包含一个整数t(1≤t≤104)- 测试用例的数量。后面是每个测试用例的描述。
每个测试用例的第一行包含一个整数n(1≤n≤2⋅105)- 吸血鬼的数量。
每个测试用例的第二行包含n个整数a1,a2,…,an(0≤ai≤109)- 每个吸血鬼的力量。
所有测试用例中n的总和不超过2⋅105。
输出:
对于每个测试用例,输出一个整数 - 在所有可能的分组方式中具有最小力量总和的最大分组数量。

思路:首先如果分成一段以上,那么一段的与一定等于零。因为如果分出的段中有非零值,那这些段的总和一定比全部与起来大(因为与运算不会使得值变大)。所以如果全部与起来不等于0,答案就是1。否则的话,就直接从前往后去找,找到一段与起来等于1的,就分一段即可。

AC代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 200010 , INF = 0x3f3f3f3f , Mod = 998244353;


int main()
{
    ll n, k;
    cin >> n;
    vector<ll> v(n+1);
    
    for(int i = 1; i <= n; i ++)
    {
        cin >> v[i];
    }
    ll now = v[1];
    for(int i = 2; i <= n; i ++)
    {
        now &= v[i];
    }
    if(now!=0)
    {
        cout << 1 << endl;
        return 0;
    }
   ll tmp = v[1];
   ll ans = 0;
    for(int i = 2; i <= n; i ++)
    {
        if(tmp == now)
        {   ans ++;
            tmp = v[i];
            continue;
        }
        tmp &= v[i];
    }
    if(tmp == now) ans ++;
    cout << ans << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值