0
点赞
收藏
分享

微信扫一扫

Codeforces Round #515 (Div. 3) 题解


文章目录

  • ​​A. Vova and Train​​
  • ​​B. Heaters​​
  • ​​C. Books Queries​​
  • ​​D. Boxes Packing​​
  • ​​E. Binary Numbers AND Sum​​
  • ​​F. Yet another 2D Walking​​

A. Vova and Train

  • 题意
    给出区间Codeforces Round #515 (Div. 3) 题解_算法,其中你想访问坐标为Codeforces Round #515 (Div. 3) 题解_c代码_02的倍数的点,而Codeforces Round #515 (Div. 3) 题解_算法_03区间是访问不了的,问你能访问多少个Codeforces Round #515 (Div. 3) 题解_c代码_02的倍数的点。
  • 解题思路
    先解决这样一个问题,Codeforces Round #515 (Div. 3) 题解_算法区间中有多少点为Codeforces Round #515 (Div. 3) 题解_c代码_02的倍数,易得为Codeforces Round #515 (Div. 3) 题解_#define_07。那么如果我们知道了Codeforces Round #515 (Div. 3) 题解_算法_03中有多少这样的点,那么两者相减自然可得。
    由于区间Codeforces Round #515 (Div. 3) 题解_算法_03存在特殊性,我们这样考虑,即先求出Codeforces Round #515 (Div. 3) 题解_#define_10Codeforces Round #515 (Div. 3) 题解_#define_11存在符合要求的点数,再两者相减即可得到。
    故此题得解。
  • AC代码
/**
*@filename:A
*@author: pursuit
*@created: 2021-08-23 20:10
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t;
ll L,v,l,r;
void solve(){
ll cnt = L / v - (r / v - (l - 1) / v);
printf("%lld\n", cnt);
}
int main(){
cin >> t;
while(t -- ){
cin >> L >> v >> l >> r;
solve();
}
return 0;
}

B. Heaters

  • 题意
    给你Codeforces Round #515 (Div. 3) 题解_#define_12个点,其中值为Codeforces Round #515 (Div. 3) 题解_c++_13代表可以放置加热器,而当第Codeforces Round #515 (Div. 3) 题解_#define_14个点放置加热器,Codeforces Round #515 (Div. 3) 题解_c++_15的点都能被加热到。问你需要放置多少加热器才能加热所有点。
  • 解题思路
    贪心的去考虑。我们用Codeforces Round #515 (Div. 3) 题解_#define_16来记录上一个放置加热器的位置,而Codeforces Round #515 (Div. 3) 题解_#define_14则为这次需要处理的初始位置,按照题目要求,我们至少要加热到Codeforces Round #515 (Div. 3) 题解_#define_14这个点,而其中能管辖到这个点的区间为Codeforces Round #515 (Div. 3) 题解_c代码_19,所以我们必须在这个区间放置一个加热器。
    那么如果我们要放置,那么肯定是放置Codeforces Round #515 (Div. 3) 题解_c代码_19这段区间最右边能放置加热器的位置,这样能使得我们覆盖的范围尽量往后移。
    至此,我们只需要按照这样来贪心放置加热器即可。
  • AC代码
/**
*@filename:B
*@author: pursuit
*@created: 2021-08-23 20:24
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e3 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n,r,a[N];
void solve(){
//last为上次使用加热器的位置。
int last = 0, res = 0, i = 1, j, k;
while(i <= n){
j = i + r - 1, k = 0;
//j为管理i的最右边的点。我们需要在j以内找到一个加热器。
if(j > n)j = n;
while(j > last){
if(a[j]){
k = j;
break;
}
else{
-- j;
}
}
if(!k){
//说明没有找到加热器。
res = -1;
break;
}
else{
last = k, i = k + r;
++ res;
}
}
printf("%d\n", res);
}
int main(){
scanf("%d%d", &n, &r);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
return 0;
}

C. Books Queries

  • 题意
    有三种操作,第一种往最左边放书,第二种往最右边放书,第三种查询取出编号为Codeforces Round #515 (Div. 3) 题解_算法_21的书的最小操作次数,只能从左边一个一个弹出书取出或者右边一个一个弹出书取出。
  • 解题思路
    这种我们很容易就想到双端队列。第一种操作和第二种操作都可以通过​​push_back(),push_front()​​实现。那么关键的一个问题就是怎么快速求出取出Codeforces Round #515 (Div. 3) 题解_算法_21的最小操作次数呢?​​deque​​肯定是不行的,因为如果我们模拟这个过程,需要真正的弹出元素,时间复杂度巨大。
    如果我们记录了每个点在双端队列中的位置以及双端队列的最左边的点和最右边的点,那么是不是可以Codeforces Round #515 (Div. 3) 题解_算法_23时间求出呢?
    所以这道题关键在于我们需要用数组实现双端队列,然后开一个数组记录每个点在队列中的位置。
    注意由于是双端队列,所以我们为了避免数组下标为负,所以我们需要偏移一个Codeforces Round #515 (Div. 3) 题解_c++_24来避免负数下标。
  • AC代码
/**
*@filename:C
*@author: pursuit
*@created: 2021-08-23 20:52
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t,x,id[N];
char op[4];
//双端队列实现。
int q[N << 1],l,r;//实现一个偏移。
void solve(){
scanf("%s%d", op, &x);
if(op[0] == 'L'){
id[x] = l;
q[l --] = x;
}
else if(op[0] == 'R'){
id[x] = r;
q[r ++] = x;
}
else{
//cout << id[x] << " " << l << " " << r << endl;
printf("%d\n", min(id[x] - l - 1, r - id[x] - 1));
}
}
int main(){
scanf("%d", &t);
l = r = N;
++ r;
while(t -- ){
solve();
}
return 0;
}

D. Boxes Packing

  • 题意
    给你Codeforces Round #515 (Div. 3) 题解_c++_25个盒子,Codeforces Round #515 (Div. 3) 题解_#define_12个物品,其中第Codeforces Round #515 (Div. 3) 题解_#define_14个物品的体积为Codeforces Round #515 (Div. 3) 题解_c++_28。你从第Codeforces Round #515 (Div. 3) 题解_c++_13个物品开始放,如果放完了所有的盒子都放不下了,就会移除第一个物品继续放,持续操作知道放完最后一个物品。问你最多能放多少个物品。
  • 解题思路
    根据题意,我们易得,最后放完的一定是后面连续的物品,所以我们只需要从后往前放知道知道放完所有的盒子且装不下了即可。此时放完的物品数就是最大的物品数了。
    当然,我们也可以二分最开始放的盒子编号。然后判断是否可行,找到最优解即可。
  • AC代码
/**
*@filename:D
*@author: pursuit
*@created: 2021-08-23 21:06
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

//从集合中扔掉最左边的元素。说明右边的一定是连续装满的。
int n,m,k,a[N];
void solve(){
int cnt = 0, i;
for(i = n; i >= 1; -- i){
if(cnt + a[i] <= k){
cnt += a[i];
}
else{
cnt = a[i], -- m;
}
if(!m){
//如果没有盒子用了。
break;
}
}
printf("%d\n", n - i);
}
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
return 0;
}

E. Binary Numbers AND Sum

  • 题意
    给定两个二进制数Codeforces Round #515 (Div. 3) 题解_c代码_30,持续以下操作直到Codeforces Round #515 (Div. 3) 题解_算法_31Codeforces Round #515 (Div. 3) 题解_#define_32
  1. 累加Codeforces Round #515 (Div. 3) 题解_#define_33
  2. Codeforces Round #515 (Div. 3) 题解_c代码_34右移一位,即Codeforces Round #515 (Div. 3) 题解_#define_35
  • 解题思路
    我们单纯模拟是不行的,因为Codeforces Round #515 (Div. 3) 题解_c代码_30的长度可达Codeforces Round #515 (Div. 3) 题解_#define_37
    那么我们换种角度考虑,由于Codeforces Round #515 (Div. 3) 题解_算法_38是不变的,Codeforces Round #515 (Div. 3) 题解_算法_31一直往右移,那么考虑Codeforces Round #515 (Div. 3) 题解_算法_31上的Codeforces Round #515 (Div. 3) 题解_c++_13的贡献,对于Codeforces Round #515 (Div. 3) 题解_算法_31的第Codeforces Round #515 (Div. 3) 题解_#define_14位的Codeforces Round #515 (Div. 3) 题解_c++_13,它会贡献Codeforces Round #515 (Div. 3) 题解_算法_38的前Codeforces Round #515 (Div. 3) 题解_#define_14位的所有的Codeforces Round #515 (Div. 3) 题解_c++_13,即与这些Codeforces Round #515 (Div. 3) 题解_c++_13进行Codeforces Round #515 (Div. 3) 题解_#define_49操作,这样得到的即为Codeforces Round #515 (Div. 3) 题解_c代码_50,其中Codeforces Round #515 (Div. 3) 题解_c代码_50表示Codeforces Round #515 (Div. 3) 题解_算法_38的前Codeforces Round #515 (Div. 3) 题解_#define_14位的十进制数值。
    所以,我们可以先预处理出Codeforces Round #515 (Div. 3) 题解_#define_54数组,然后累加Codeforces Round #515 (Div. 3) 题解_算法_31上的所有Codeforces Round #515 (Div. 3) 题解_c++_13的贡献即可。
  • AC代码
/**
*@filename:E
*@author: pursuit
*@created: 2021-08-23 21:31
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 998244353;
const int INF = 0x3f3f3f3f;

//考虑贡献,每个移动一次就相当于在a中贡献了一次。累加前缀和即可。
int n,m,sum[N];
char a[N],b[N];
int ksm(int n, int q){
int ans = 1;
while(q){
if(q & 1)ans = 1LL * ans * n % P;
q >>= 1;
n = 1LL * n * n % P;
}
return ans;
}
void solve(){
//我们需要从低位处理到高位。为了方便,所以我们需要反转字符串。
reverse(a + 1, a + 1 + n);
reverse(b + 1, b + 1 + m);
for(int i = 1; i <= n; ++ i){
if(a[i] == '1'){
sum[i] = ksm(2, i - 1);
}
}
for(int i = 1; i <= m; ++ i){
sum[i] = (sum[i] + sum[i - 1]) % P;
}
int res = 0;
for(int i = 1; i <= m; ++ i){
//考虑每一位的贡献。
if(b[i] == '1'){
res = (res + sum[i]) % P;
}
}
printf("%d\n", res);
}
int main(){
scanf("%d%d", &n, &m);
scanf("%s%s", a + 1, b + 1);
solve();
return 0;
}

F. Yet another 2D Walking

  • 题意
    给你Codeforces Round #515 (Div. 3) 题解_#define_12个点,定义每个点Codeforces Round #515 (Div. 3) 题解_算法_58属于Codeforces Round #515 (Div. 3) 题解_#define_59级别。初始你处于Codeforces Round #515 (Div. 3) 题解_算法_60,即第Codeforces Round #515 (Div. 3) 题解_#define_32个级别。规定你访问第Codeforces Round #515 (Div. 3) 题解_#define_14级别的时候前Codeforces Round #515 (Div. 3) 题解_c代码_63级别的所有点都要访问完。问访问完所有点的最短距离。
  • 解题思路
    我们需要清楚,在同一个Codeforces Round #515 (Div. 3) 题解_c++_64中必须要访问所有的点。那么我们必然会有一个起始点和终止点,而从一个级别跳到另一个级别也是从这些点跳转的。所以我们要规划起始点和终止点。这里设置从上往下,从左往右。也可以按其他方式排列。但一定要保证在这个Codeforces Round #515 (Div. 3) 题解_c++_64中的起始点和终止点一定是最外面的点。
    我们可以用Codeforces Round #515 (Div. 3) 题解_c++_66来表示访问到第Codeforces Round #515 (Div. 3) 题解_c++_67Codeforces Round #515 (Div. 3) 题解_#define_68Codeforces Round #515 (Div. 3) 题解_算法_69点的最小距离。
    其中Codeforces Round #515 (Div. 3) 题解_算法_69Codeforces Round #515 (Div. 3) 题解_#define_71代表第一个点,Codeforces Round #515 (Div. 3) 题解_算法_69Codeforces Round #515 (Div. 3) 题解_算法_73代表最后一个点,即可以通过上一个Codeforces Round #515 (Div. 3) 题解_#define_68的第一个点或者最后一个点得来。

    根据以上分析,状态转移方程就很好列出了。
    Codeforces Round #515 (Div. 3) 题解_算法_75可以通过Codeforces Round #515 (Div. 3) 题解_c++_76Codeforces Round #515 (Div. 3) 题解_算法_77得来,这个意思是从第Codeforces Round #515 (Div. 3) 题解_c代码_63Codeforces Round #515 (Div. 3) 题解_c++_64的第一个点或者最后一个点跳到第Codeforces Round #515 (Div. 3) 题解_#define_14Codeforces Round #515 (Div. 3) 题解_c++_64的最后一个点,再从最后一个点访问第一个点 (这样这个level中的其他的点在这个路径中也都放访问了)
    其他状态同理可列举。
  • AC代码
/**
*@filename:F
*@author: pursuit
*@created: 2021-08-23 22:02
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
#define x first
#define y second

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n,m;
map<int,vector<pii> > levels;//存储每个级别的坐标点。
pii a,b,c,d;
ll dp[N][2];
bool cmp(pii a,pii b){
if(a.x == b.x){
return a.y > b.y;//列相同,按行排序。
}
return a.x < b.x;
}
int dist(pii a,pii b){
return abs(a.x - b.x) + abs(a.y - b.y);
}
void solve(){
levels[0].push_back({0,0});
for(auto &it : levels)sort(it.second.begin(), it.second.end(), cmp);
fill(dp[0], dp[0] + N * 2, 1e18);
dp[0][0] = dp[1][0] = 0;//初始化。
int cur = 0, pre = 0;
for(auto &it : levels){
++ cur;
//取出当前级别第一个点和最后一个点。
a = it.second[0], b = it.second.back();
//取出先前级别第一个点和最后一个点。
c = levels[pre][0], d = levels[pre].back();
dp[cur][0] = min(dp[cur][0], dp[cur - 1][0] +
dist(c,b) + dist(b,a));
dp[cur][0] = min(dp[cur][0], dp[cur - 1][1] +
dist(d,b) + dist(b,a));
dp[cur][1] = min(dp[cur][1], dp[cur - 1][0] +
dist(c,a) + dist(a,b));
dp[cur][1] = min(dp[cur][1], dp[cur - 1][1] +
dist(d,a) + dist(a,b));
pre = it.first;
}
printf("%lld\n", min(dp[cur][0], dp[cur][1]));
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d%d", &a.x, &a.y);
levels[max(a.x,a.y)].push_back(a);
}
solve();
return 0;
}


举报

相关推荐

0 条评论