Codeforce - 1191C - Tokitsukaze and Discard Items - 模拟

https://codeforces.com/contest/1191/problem/C
一开始想象了一下,既然每次删除都是往前面靠,那么好像就是页数*页容量+空位数=最多容纳到的坐标。
至于为什么呢?好像是每次都会删除干净的原因,从第一页开始考虑,第一页可以容纳到5,这个很显然。
删除之后有2个空位,然后可以容纳到7。再把7也删除,就可以容纳到8。

那么每次就暴力删除特殊元素就可以了,反正最多就是m个。

问题在于翻页的时候不能够简单的curpage++,这样必定翻车。我是直接二分,因为顶多就是分m次logn,非常小。看了别人的可以每次O(1)得到。
具体的做法是:比如现在取不出队首的元素a[i]了,直接翻到哪一页呢?最多容纳到的坐标要比a[i]大,用a[i]减去空位数,就可以得到它当前的坐标,记做b[i],那么所需的页数就是包含b[i]的最小的k的倍数,自然就是(b[i]+k-1)/k*k。

不过复杂度都是对的,有个数组越界bug但是却没事?

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll n, k;
int m;
int sumdiscard = 0;
ll curpage = 1;
int ans = 0;
int _begin = 1;
ll max_delta;

ll a[100005];

ll find_delta() {
    ll l = 1, r = max_delta;
    while(1) {
        ll m = l + r >> 1;
        if(m == l) {
            if(k * (curpage + l) + sumdiscard >= a[_begin]) {
                //足够大
                return l;
            } else {
                return r;
            }
        }
        if(k * (curpage + m) + sumdiscard >= a[_begin]) {
            //足够大
            r = m;
        } else {
            //不够大
            l = m + 1;
        }
    }
}

int main() {
    scanf("%lld%d%lld", &n, &m, &k);
    max_delta = (n + k - 1) / k;
    for(int i = 1; i <= m; i++) {
        scanf("%lld", &a[i]);
    }
    while(sumdiscard < m) {
        if(curpage * k + sumdiscard >= a[_begin]) {
            //至少有一个特殊元素要被删除
            int cnt = 0;
            while(curpage * k + sumdiscard >= a[_begin]) {
                _begin++;
                cnt++;
            }
            sumdiscard += cnt;
            ans++;
        } else {
            curpage += find_delta();
            //效率可能过低
        }
    }
    printf("%d\n", ans);
}

当然既然每次都是去k的倍数干脆curpage就不用乘k了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll a[100005];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
    //freopen("Yinku.out", "w", stdout);
#endif // Yinku
    ll n, k;
    int m;
    while(~scanf("%lld%d%lld", &n, &m, &k)) {
        for(int i = 1; i <= m; i++) {
            scanf("%lld", &a[i]);
        }
        int sumdiscard = 0, ans = 0, _begin = 1;
        ll curpage = k;
        while(sumdiscard < m) {
            if(curpage + sumdiscard >= a[_begin]) {
                //至少有一个特殊元素要被删除
                int cnt = 0;
                while(_begin <= m && curpage  + sumdiscard >= a[_begin]) {
                    _begin++;
                    cnt++;
                }
                sumdiscard += cnt;
                ans++;
            } else {
                curpage = (a[_begin] - sumdiscard + k - 1) / k * k ;
            }
        }
        printf("%d\n", ans);
    }
}

原文地址:https://www.cnblogs.com/Yinku/p/11179235.html

时间: 2024-10-13 16:25:09

Codeforce - 1191C - Tokitsukaze and Discard Items - 模拟的相关文章

Codeforce 264 B Caisa and Pylons(模拟)

 题意   Caisa走台阶  有n个台阶  第i个台阶的高度为h[i]  从第i个台阶包括地面到下一个台阶得到的能量为h[i]-h[i+1]  能量不足以跳到下一个台阶就要补充能量  求Caisa跳完所有台阶最少要补充多少能量 水题   直接模拟 #include<cstdio> #include<cstring> using namespace std; const int N = 100005; int h[N]; int main() { int n, e, ans;

CodeForce 7 B - Memory Manager(模拟)

题目大意:给你一段内存,要你进行如下的三个操作. 1.分配内存  alloc   X ,分配连续一段长度为X的内存. 如果内存不够应该输出NULL,如果内存够就给这段内存标记一个编号. 2.擦除编号为 X的内存,erase X,  如果这段内存不存在那么输出“ILLEGAL_ERASE_ARGUMENT ”,否则什么都不输出. 3.整理内存,把所有的内存块整理到一块. #include<cstdio> #include<cstring> #include<iostream&g

取整问题

首先是整数类型 设 ll a,k; 求a/k  向上取整 ans=(a-1)/k+1; 求a/k 向下取整 ans=(a-1)/k; int/int 是整除 强制类型转化 等 都是向下取整 例题 codeforce  C - Tokitsukaze and Discard Items Codeforces Round #572 (Div. 2) https://codeforces.com/contest/1191/problem/C C. Tokitsukaze and Discard Ite

Codeforces Round #573 (Div. 2) A B C

ATokitsukaze and Enhancement #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+100; int x; int main(){ cin >> x; int cnt = 0; if( x%4 <= 1 || x%4==3){ if (x%4==0) cnt=1; if(x%4 ==3) cnt=2; cout << cnt

Codeforce 371A K-Periodic Array(模拟)

题目链接 K-Periodic Array 简单题,直接模拟即可. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i,n) for(int i(0); i < (n); ++i) 6 #define rep(i,a,b) for(int i(a); i <= (b); ++i) 7 const int N = 100000 + 10; 8 9 int a[N]; 10 int n, k; 11

Kilani and the Game-吉拉尼的游戏 CodeForce#1105d 模拟 搜索

题目链接:Kilani and the Game 题目原文 Kilani is playing a game with his friends. This game can be represented as a grid of size ??×??, where each cell is either empty or blocked, and every player has one or more castles in some cells (there are no two castle

Codeforce 522C - Chicken or Fish? 模拟

//思路:因为题目是要求求出所有可能被选完的 dish,所以当之前乘客所选 dish 不确定时,将所有 dish 的数量均减一(做法是记录下来不确定的 dish 的数量):当出现第一个顾客 QAQ(不开心) 的时候,说明在他之前至少有一个 dish 已经被选完了,这时候就需要利用不确定的 dish 的数量优先构造出一个被选完的 dish(注意到之后被选择的 dish 一定不能再此刻被选完) //感觉这题要是题目读懂了就没什么难度了......弱渣这题读了好半天 Orz 1 #include "b

CodeForce 508C Anya and Ghosts (贪心+模拟)

题目大意:有m个时刻,在第i时刻即wi秒的时候需要保持有r根蜡烛亮着,每根蜡烛维持的时间为t秒,点一根蜡烛需要1秒. 注意:一根蜡烛亮的时间为下一秒开始.并且一开始是可以事先准备蜡烛的. 想法:利用了优先队列,维护r根蜡烛,每次wi秒,它需要开始点蜡烛的最晚时间为wi-t,如果不够这个时间,那么在最晚结束点蜡烛的时间wi-1开始补上. 感谢阿扎夫人提供的思维题. AC代码: #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include&

codeforce 1025C - Plasticine zebra (模拟)

有一个由'w'和'b'组成字符串,你可以把这个字符串分成两个部分,然后分别翻转,次数不限(比如bw|bbw ('|'代表分割线), 翻转之后变成 "wbwbb".).问你连续的'w' 'b' 交替出现的最长长度是多少. 我们观察这个操作的特点,发现其实就像相当于把这个串的首尾相连,然后在分隔处截断.也就是说,如果我们把这个字符串看成首尾相连的一个环,那么,不管怎么操作,这些字母的相对位置都是不会改变的,也就是说,我们直接统计这个环里面的最长交替出现的长度即可. 至于怎么把它看成一个环,