Codeforces #509 div2 1041 ABCD

A. Heist

商店里的键盘都是从某个数开始连续编号的,有一些键盘被盗了,现在给你剩下的键盘编号,求最少被盗了多少个键盘

排个序检查一下就好了。。。

#include 
#include 
#include 
#include 
#include 
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
int n,a[MAXN],ans;
int main() {
    scanf("%d", &n);
    for(int i=1; i<=n; i++) {
        scanf("%d", &a[i]);
    }
    sort(a+1, a+n+1);
    int sta = a[1];
    for(int i=1; i<=n; i++) {
        while(sta++ < a[i]) {
            ans++;
        }
    }
    printf("%d", ans);
    return 0;
}

B. Buying a TV Set

求w<=a, h<=b 且w/h = x/y 的正整数对(w, h)的个数

枚举可以过n^2,怎么优化。。。
可以发现满足要求的w/h 等于 k * (x/y)
也就是说(w, h) = (kx, ky)
有坑点!!! 先把x/y化为最简分数(样例真良心,包含了这种情况)

#include 
#include 
#include 
#include 
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
typedef long long ll;
ll n,a,b,x,y;
ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a%b); 
}
int main() {
    cin >> a >> b >> x >> y;
    ll temp = gcd(x, y);
    x /= temp, y /= temp;
    ll q1 = a/x, q2 = b/y;
    ll fin = min(q1, q2);
    cout << fin;
    return 0;
}

C. Coffee Break

Monocarp需要在给定时刻( a1 a 1 ~ an a n )喝点咖啡休息1分钟,每天时间长度为m(这个条件没啥用,因为若 ai>m a i > m 则Monocarp永远喝不到那杯咖啡,输入也保证了 aim a i ≤ m ),然而Monocarp的老板说他必须在两次喝咖啡之间隔开d分钟(假设d = 3,1min时喝了咖啡,则必须5min时才能再喝咖啡,中间隔了2,3,4三分钟)所以他得分好多天喝完给定时刻的咖啡。现在问最少花费天数以及方案(输出一个任意方案即可)

本来排序乱模拟了一遍。。。后来发现用set就能解决这个问题
把ai的值和次序搞一个pair放到set,因为set中的元素都是有序的,所以每次都找begin的元素作为一天的开始,然后在set里不断二分找接下来相隔d分钟的下一个休息时间,注意找到了就删掉。。。
pair默认优先比较first元素再比较second,所以下面的lower_bound的第二个参数为0是最好的,这样任何元素的第二键值都会大于新造的pair

#include 
#include 
#include 
#include 
#include 
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
typedef long long ll;
int n,m,d,ans[MAXN],tot,a[MAXN];
setint, int> > s;
int main() {
    scanf("%d%d%d", &n, &m, &d);
    for(int i=1; i<=n; i++) {
        scanf("%d", &a[i]);
        s.insert(make_pair(a[i], i));
    }
    while(!s.empty()) {
        tot++;
        int pos = s.begin()->second;
        ans[pos] = tot;
        s.erase(s.begin());
        while(1) {
            setint, int> > :: iterator it = s.lower_bound(make_pair(a[pos]+d+1, 0)); 
            if(it == s.end()) break;
            pos = it->second;
            ans[pos] = tot;
            s.erase(it);
        }
    }
    printf("%d\n", tot);
    for(int i=1; i<=n; i++) {
        printf("%d ", ans[i]);
    }
    return 0;
}

D. Glider

给定挂载滑翔机的初始高度,滑翔机可以从任意位置(横坐标)跳下,有一些互不相交上升气流区间(按升序给出),滑翔机在这些区间内滑行不会下降,其他区间内每在x轴跑一个单位长度,y轴随之下降一个单位长度,当滑翔机高度为0时,不能通过上升气流再滑动
求滑翔机最多能滑多远(投影到x轴上的位移)

最后答案一定是某些区间的长度之和加上给的h,把区间缩成点,点权是区间长度,预处理出两个区间之间的距离,当成边连着区间,一个朴素的想法是枚举起点,一直往右走,统计一下答案
但是考虑到这样会重复走很多已经走过的路径,考虑到起点是连续的,上一次走过的路径这次应该能用上一部分,维护一下就好了。具体来说就是设一个剩下的“长度”rem(rem一开始为h),当起点从i到i+1时,rem加上从i到i+1的花费,然后再试试用rem能否走到以i为起点走到的最右边,再往右的一些点(保留上次最后的位置),同时注意维护sum,既然不以i为起点,i的点权的贡献也要消去

#include 
#include 
#include 
#include 
#include 
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
typedef long long ll;
int n,m,last[MAXN],ans,rem,h,nxt[MAXN],val[MAXN];
struct segment{
    int l, r;
}seg[MAXN];
int main() {
    scanf("%d%d", &n, &h);
    for(int i=1; i<=n; i++) {
        scanf("%d%d", &seg[i].l, &seg[i].r);
        val[i] = seg[i].r - seg[i].l;
    }
    for(int i=2; i<=n; i++) {
        int sta = seg[i-1].r, ed = seg[i].l;
        int w = ed - sta;
        nxt[i-1] = w;
    }
    rem = h;
    int pos = 1;
    int sum = val[1];
    for(int i=1; i<=n; i++) {
        while(1) {
            if(rem - nxt[pos] <= 0 || pos > n) break;
            rem -= nxt[pos];
            pos++;
            sum += val[pos];
        }
        rem += nxt[i];
        ans = max(ans, sum + h);
        sum -= val[i];
    }
    printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(Codeforces)