随笔 - 164  文章 - 0  评论 - 4  阅读 - 9797

Codeforces Round 888 (Div. 3) - D(思维) E(toposort) F(位运算贪心)

Codeforces Round 888 (Div. 3) 赛后摘记

ABCD简单题


A : O(n)判断每一个人与 Vlad 的高度差是不是楼梯高 k 的 c 整数倍 (1c<m)

void solve(){
ll n, m, k, H;
cin >> n >> m >> k >> H;
vector<ll> h(n + 1);
ll ans = 0;
for(int i = 1; i <= n; ++ i){
cin >> h[i];
if(abs(h[i] - H) % k == 0 && abs(h[i] - H) / k < m && h[i] != H){
++ ans;
// debug(i);
}
}
cout << ans << '\n';
return ;
}

B :先对整个数组进行非递减排序,再依次判断排序数组和原数组每一位上的模2余数是否都相同即可

void solve(){
int n;
cin >> n;
vector<int> a(n), b(n);
for(int i = 0; i < n; ++ i){
cin >> a[i];
b[i] = a[i];
}
sort(b.begin(), b.end());
for(int i = 0; i < n; ++ i){
if(a[i] % 2 != b[i] % 2){
cout << "NO\n";
return ;
}
}
cout << "Yes\n";
return ;
}

C :最简单的方法,因为只需要判断能否抵达终点,那么先找起点出去有没有 k 块起点颜色,找到 k 块后再开始统计后面的颜色,最后判断终点的颜色的砖块数是否多于 k 块即可

void solve(){
int n, k;
cin >> n >> k;
vector<int> c(n);
map<int,int> q;
bool f = false;
for(int i = 0; i < n; ++ i){
cin >> c[i];
if(c[i] == c[0] && !f){
++ q[c[0]];
if(q[c[0]] == k){
f = true;
}
}else if(f){
++ q[c[i]];
}
}
if(q[c[n - 1]] >= k) cout << "YES\n";
else cout << "NO\n";
return ;
}

D. Prefix Permutation Sums

题意
判断给定的长为n - 1数组,是否为某个 1 ~ n 的序列的前缀和数组漏了一个数形成的数组

思路
就是判断能否变回去,毫无感情的判断机器
统计给定前缀和数组的差分数组得到所有的目前有的 n - 1 个数,那么如果他是,要么它仅缺失了首尾的前缀数字,或者说,就是重复了一个数或者大于n一个数且这个数为整体缺失的两个数之和

代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
void solve(){
int n;
cin >> n;
vector<ll> a(n + 1, 0), b;
vector<bool> vis(n + 1, false);
for(int i = 1; i < n; ++ i){
cin >> a[i];
ll t = a[i] - a[i - 1];
if(t <= n){
if(vis[t]) b.push_back(t);
vis[t] = true;
}else b.push_back(t);
}
vector<ll> ne;
for(int i = 1; i <= n; ++ i){
if(!vis[i]) ne.push_back(i);
}
if(ne.size() == 1 && b.size() == 0){
cout << "YES\n";
return ;
}
if(ne.size() == 2 && b.size() == 1){
if(b[0] == ne[0] + ne[1]){
cout << "YES\n";
return ;
}
}
cout << "NO\n";
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}

E. Nastya and Potions

题意
题面有点长,慢慢读即可
有 n 种药剂,每种药剂在市面上都有一个价格 c,其中 k 种你自己就有货,不需要买。每一种药剂都有一个合成配方,没有合成配方的药剂只能买。问你所有获得每种药剂的花费(要么买,要么合成)

思路

  • 对于已经有的药剂,花费为0
  • 对于剩下的药剂,只需要比较买的价格和合成的价格哪个便宜就选则哪种方式

注意到药剂合成的相互牵制关系,所以我们将合成关系抽象成 DAG,再利用 toposort 处理先后顺序即可。简单来说就是 toposort 的简单题

代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const ll maxm = 2e5 + 5, inf = 0x3f3f3f3f3f3f3f3f, mod = 998244353;
void solve(){
int n, k;
cin >> n >> k;
vector<ll> c(n + 1), p(n + 1, 0);
for(int i = 1; i <= n; ++ i){
cin >> c[i];
}
ll t;
for(int i = 1; i <= k; ++ i){
cin >> t;
c[t] = 0; //这种药剂花费为 0
}
vector<int> mix[n + 1], in(n + 1, 0);
for(int i = 1; i <= n; ++ i){
int m;
cin >> m;
while(m --){
cin >> t;
mix[t].push_back(i);
++ in[i];
}
}
queue<int> q;
for(int i = 1; i <= n; ++ i){
if(in[i] == 0){
p[i] = c[i]; //这种药剂只能买
q.push(i);
}
}
while(q.size()){
t = q.front(); q.pop();
c[t] = min(c[t], p[t]); //购买与合成取最小
for(auto x : mix[t]){
-- in[x];
if(in[x] == 0) q.push(x);
p[x] += c[t]; //向下更新合成花费
}
}
for(int i = 1; i <= n; ++ i){
cout << c[i] << " \n"[i == n];
}
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}

F. Lisa and the Martians

题意
给你长为 n 的数组 a [1 ~ n] ,数组 a 的所有元素均为非负整数且严格小于 2k,这样的数被称为火星数字
让你从数组 a 中选择两个数,下标为 i 和 j ,再确定一个火星数字 x ,使得式子(aix)&(ajx)最大

思路
y=(aix)&(ajx)
x 异或的作用就是决定 aiaj 的同一位翻转与否,之后再进行位与操作。那么要想最后的值最大,我们需要让每一位都尽可能是 1。对于二进制中的某一位 m,当aim=ajm=b时,应取 xm=b,此时 ym=1 ;当aimajm时,无论怎么取 xmym 均等于 0
所以,我们需要让 aiaj 二进制中相同的位数尽可能多,也就是两者异或和尽可能小。有个结论:一个数组选两个数的异或和最小值出现在排序之后的相邻数之间。在知道这个结论之后,aiaj 已经确定,至于数 x,我们只需要让 aiaj 二进制相同的位上让 x 取反,其余位随意即可。一种可能的方式就是 x=(2k1)(ai|aj) 或者x=(2k1)(ai&aj)

也可以利用trie数求解异或最小。题目的关键在于发现异或最小这一隐藏条件。

代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
void solve(){
int n, k, t;
cin >> n >> k;
vector<pii> a(n);
for(int i = 0; i < n; ++ i){
cin >> t;
a[i] = {t, i + 1};
}
sort(a.begin(), a.end());
int ans = (1 << k), x, y, z;
for(int i = 1; i < n; ++ i){
int t = a[i].first ^ a[i - 1].first;
if(t < ans){
ans = t;
y = a[i].second;
z = a[i - 1].second;
x = ((1 << k) - 1) ^ (a[i].first | a[i].first);
}
}
cout << y << ' ' << z << ' ' << x << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
cin >> _;
while(_ --){
solve();
}
return 0;
}
posted on   Qiansui  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示