Codeforces Round 885 (Div. 2) 蹄解

文章讲述了两个编程问题,第一个关于Vika如何在涂色的木桥上行走,避免破坏不同颜色的木板,求出最少跨越的最大木板数。第二个问题是Vika分析化妆品价格变化,通过多次计算价格差判断价格数组是否无聊(所有元素变为零)。
摘要由CSDN通过智能技术生成

https://codeforces.com/contest/1848


A:略


 

B. Vika and the Bridge

题意:

夏天,Vika喜欢去她的乡间小屋度假。那里有一切可以放松的设施:舒适的秋千、自行车和一条小河。

小河上有一座由n块木板组成的木桥。这座桥相当老旧和不吸引人,所以Vika决定给它上色。在小屋里,他们刚刚找到了k种颜色的油漆罐。

在将每块木板涂成k种颜色之后,Vika本打算去荡秋千休息一下。然而,她意识到房子在河的另一边,油漆还没有完全干透,所以她还不能走在桥上。

为了不破坏桥的外观,Vika决定她还是会走在桥上,但只踩着相同颜色的木板。否则,她鞋底上的一小层油漆会破坏其他颜色的木板。Vika还剩下一点油漆,但只够重新粉刷一块木板的颜色。

现在,Vika站在第一块木板前的地面上。为了穿过桥,她将选择一些颜色相同的木板(重新粉刷后),其编号为1≤i1<n(木板从左到右编号为1)。然后,Vika将必须越过i1−1,i2−i1−1,i3−i2−1,…,im−im−1−1,n−im
块作为每个m+1
步的结果。

由于Vika害怕摔倒,她不想迈太大的步子。请帮助她,并告诉她在一步中要越过的最少可能的最大数量的木板,如果她可以在过桥时重新粉刷一块(或零块)木板的颜色。

输入
每个测试由多个测试用例组成。第一行包含一个整数t(1≤t≤104) - 测试用例的数量。以下是每个测试用例的描述。

每个测试用例的第一行包含两个整数n和k(1≤k≤n≤2⋅105) - 桥上木板的数量和油漆的不同颜色数。

每个测试用例的第二行包含n个整数c1,c2,c3,…,cn(1≤ci≤k) - Vika涂在桥上木板上的颜色。

保证所有测试用例中n的总和不超过2⋅105。

输出
对于每个测试用例,输出一个整数 - Vika在一步中必须跨越的最少可能的最大数量的木板。


蹄解:

首先我们要知道可以改变其中的一块砖头的颜色,假如一种颜色的分布是(这里假设A为该颜色,B为其它颜色),其中一段为ABBBBBA,中间为5个为奇数,如果要放肯定是要尽量让最大值变小,让放完以后的最大值和次大值进行比较,假设放的位置以后两边得到的最大值是k,ans = max(k, 次大值),两边取最小的时候才能让k尽量小,答案向尽量小的位置更逼近。

所以枚举每种颜色的最大值和次大值,取max(次大值,最大值 / 2);

 CODE: 

#include <iostream> 
#include <algorithm> 
#include <cstring> 
#include <map> 
#include <bits/stdc++.h> 
using namespace std; 
const int N = 2e5 + 10, INF = 0x3f3f3f3f; 
int n, m; 
int a[N]; 

void solve() 
{
    cin >> n >> m; 
    vector<int> b[n + 2]; 
    map<int, int> mp; 
    
    int idx = 0; 
    for(int i = 1; i <= n; i ++ ) 
    {
        cin >> a[i]; 
        if(mp.count(a[i]) == 0) mp[a[i]] = ++ idx;  
        b[mp[a[i]]].push_back(i); 
    }
    
    int ans = INF; 
    for(int i = 1; i <= idx; i ++ ) 
    {
        b[i].push_back(n + 1); 
        int q = -INF, u = -INF;  
        for(int j = 0; j < b[i].size(); j ++ ) 
        {
            int d; 
            if(!j) d = b[i][j] - 1; 
            else d = b[i][j] - b[i][j - 1] - 1; 
            
            if(d >= q) u = q, q = d; 
            else if(d > u) u = d;
        }
        
        q = max(q / 2, u); 
        
        ans = min(ans, q); 
    
    }
    cout << ans << endl; 
    
}
int main() 
{
    int _; 
    cin >> _; 
    while(_--) solve(); 
    
    return 0; 
}


D. Vika and Bonuses

题意:

Vika来到了她最喜欢的化妆品店"Golden Pear"。她注意到自己上次来店里以后,n个物品的价格发生了变化。

她决定分析价格的变化,并计算每个物品的新旧价格差异。

Vika喜欢计算价格差异,并决定继续这个过程。

假设旧价格表示为非负整数数组a,新价格表示为非负整数数组b。这两个数组有相同的长度n。

在一个操作中,Vika根据以下原则构建一个新数组c:ci = |ai - bi|。然后,数组c重命名为数组b,数组b同时重命名为数组a,之后Vika用它们重复这个操作。

例如,如果a = [1,2,3,4,5,6,7],b = [7,6,5,4,3,2,1],那么c = [6,4,2,0,2,4,6]。然后,a = [7,6,5,4,3,2,1],b = [6,4,2,0,2,4,6]。

Vika认为如果经过一些操作,数组a的所有元素都变成零,那么原始的数组对a,b是无聊的。

如果原始的数组对是无聊的,输出"YES",否则输出"NO"。

输入
每个测试由多个测试用例组成。第一行包含一个整数t(1≤t≤104) - 测试用例的数量。以下是每个测试用例的描述。

每个测试用例的第一行包含一个整数n(1≤n≤105) - 价格发生变化的物品数量。

第二行包含n个整数a1,a2,…,an(0≤ai≤109) - 物品的旧价格。

第三行包含n个整数b1,b2,…,bn(0≤bi≤109) - 物品的新价格。

保证所有测试用例中n的总和不超过105。

输出
对于每个测试用例,如果价格数组对是无聊的,则输出"YES",否则输出"NO"。

你可以以任何形式输出(小写或大写)每个字母。例如,字符串"yEs","yes","Yes"和"YES"都将被接受为肯定的答案。


蹄解: 

两个数进行交替操作以后,一定会变成三类数字, 第一种就是一边为0的数字,这种的前驱是两个数相等的情况,还有一种是两个都为0的情况,前者一边为0的情况,是有周期的:

0   x  x 0  x  ....

x   x  0  x  x ....

这种情况是有周期的,利用这一点还可以优化代码的复杂度。

所以最后就是统计所有a[i]和b[i]要满足条件需要的步数,如果按照顺序是i..... 最大是j,如果

j == i + 3 * k(k >= 0)对于所有i满足,那最后的答案一定满足,两边取%,j % 3 == i  % 3 + 0 == i

所以最后是j % 3 == i % 3,所以统计每个步骤数%3以后的结果,结果只能为1个

对于统计每两个数的步骤数,是要有一个优化的,

比如x = a[i], y = b[i] 

x   y 

y   abs(x - y) 

当x >= 2 * y的时候 可以直接向前3步,

x   y       x - y        x - 2 * y

y   x - y   x - 2 * y     y 

最好就能省去很多的步骤和数,这步优化是真的很妙

CODE:

#include <iostream> 
#include <algorithm> 
#include <cstring>
#include <set>
#include <map>
#define PII pair<int, int> 
using namespace std; 
const int N = 2e5 + 2, M = 210, INF = 0x3f3f3f3f; 
int n, m; 
int a[N], b[N]; 
void hhh() 
{
    cin >> n; 
    for(int i = 1; i <= n; i ++ ) cin >> a[i]; 
    for(int i = 1; i <= n; i ++ ) cin >> b[i]; 
    set<int> op; 
    int ans = -INF; 
    for(int i = 1; i <= n; i ++ ) 
    {
        int x = a[i], y = b[i];
        int v = 0; 
        if(!x && !y) continue; 
        while(x) 
        {
            if(x >= 2 * y && y) x %= 2 * y, v += 3;  
            else 
            {
                int t = abs(x - y);  
                x = y; 
                y = t; 
                v ++; 
            }
        }
        op.insert(v % 3); 
    }
    
    if(op.size() >= 2) puts("NO"); 
    else puts("YES"); 
    
}
int main() 
{
    int _; 
    cin >> _; 
    while(_--) hhh(); 
    
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘗_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值