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